HIGH http request smugglingactixmutual tls

Http Request Smuggling in Actix with Mutual Tls

Http Request Smuggling in Actix with Mutual Tls — how this specific combination creates or exposes the vulnerability

HTTP request smuggling occurs when an attacker sends a specially crafted request that is interpreted differently by the frontend (terminating TLS) and the backend (Actix server). In setups that use Mutual TLS (mTLS), the frontend terminates client certificate validation before forwarding the request. If the frontend and Actix interpret header boundaries differently—typically due to inconsistent handling of Content-Length versus Transfer-Encoding or malformed chunked bodies—an attacker can smuggle a request that is cached, routed to a different tenant, or executed with elevated trust.

With mTLS, the frontend validates the client certificate and may strip or rewrite headers before forwarding. If the forwarding logic does not normalize the request exactly as Actix would when listening directly, smuggling becomes possible. For example, a request with both Content-Length and Transfer-Encoding may be accepted by the frontend (which may prioritize one header) but rejected or interpreted differently by Actix. Because mTLS hides the original client certificate from Actix, the backend may lack context to enforce the same strict validation, allowing a smuggled request to bypass intended access controls or be logged with incorrect identity context.

An attacker can exploit this to perform BOLA/IDOR by smuggling a request intended for one user to be processed under another user’s identity, or to bypass authentication checks that the frontend applies but Actix does not re-validate. In an API security scan, such inconsistencies appear as findings in the BOLA/IDOR and Authentication checks, and may be reflected in an insecure Encryption finding when mTLS is not consistently enforced end-to-end.

Consider an OpenAPI spec defining an endpoint that requires strict header and body parsing. If the frontend normalizes Transfer-Encoding: chunked but Actix receives the same request without that normalization, the body boundary may be misaligned. This misalignment can cause Actix to treat part of the attacker’s smuggling payload as the next request. Because mTLS terminates at the frontend, Actix never sees the original client certificate, so it cannot correlate the request to a verified identity, increasing the impact of the smuggled request.

Mutual Tls-Specific Remediation in Actix — concrete code fixes

To mitigate request smuggling when using mTLS with Actix, ensure the frontend and Actix apply identical parsing rules and that Actix validates or normalizes headers consistently. Do not rely on the frontend to enforce security checks that Actix also needs to enforce.

In Actix, configure TLS termination with client certificate verification and enforce header normalization before routing. Below is a complete, syntactically correct example of an Actix server with mTLS that validates client certificates and ensures consistent header handling to reduce smuggling risk.

use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use actix_web::http::header::{HeaderValue, CONTENT_LENGTH, TRANSFER_ENCODING};
use actix_web::dev::ServiceRequest;
use actix_web::middleware::Next;
use std::sync::Arc;

// A guard that ensures Content-Length and Transfer-Encoding are not both present.
async fn validate_headers(req: ServiceRequest, next: Next) -> impl Responder {
    let headers = req.headers();
    let has_content_length = headers.contains_key(CONTENT_LENGTH);
    let has_transfer_encoding = headers.contains_key(TRANSFER_ENCODING);

    if has_content_length && has_transfer_encoding {
        return HttpResponse::BadRequest().body("Conflicting headers: Content-Length and Transfer-Encoding");
    }
    next.call(req).await
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    // Paths to PEM files; in production these come from secure secrets.
    let cert_path = "certs/server.crt";
    let key_path = "certs/server.key";
    let client_ca_path = "certs/client-ca.crt";

    // Load server certificate and key.
    let server_cert = std::fs::read(cert_path).expect("unable to read server cert");
    let server_key = std::fs::read(key_path).expect("unable to read server key");

    // Configure TLS acceptor with client verification.
    let mut builder = native_tls::TlsAcceptor::builder(
        native_tls::Identity::from_pkcs8(&server_cert, &server_key)
            .expect("invalid server identity"),
    );
    builder.client_auth(native_tls::ClientAuthMode::Verify);
    builder.add_client_ca(
        native_tls::Certificate::from_pem(&std::fs::read(client_ca_path)
            .expect("unable to read client CA"))
        .expect("invalid client CA"),
    );
    let tls_acceptor = Arc::new(builder.build().expect("failed to build TLS acceptor"));

    HttpServer::new(move || {
        App::new()
            .wrap_fn(|req, next| validate_headers(req, next))
            .service(web::resource("/api/ingest")
                .route(web::post().to(|| async { HttpResponse::Ok().body("ok") })))
    })
    .bind_openssl("127.0.0.1:8443", tls_acceptor.clone().into_openssl_acceptor().unwrap())
    .expect("bind failed")
    .run()
    .await
}

This example shows server-side TLS with client certificate verification using native-tls. The validate_headers guard rejects requests with both Content-Length and Transfer-Encoding, preventing a common smuggling vector. In production, also normalize headers (e.g., lowercasing, removing any frontend-added hop-by-hop headers) before Actix sees them, and ensure the frontend does not suppress or misinterpret chunked encoding when mTLS is in use.

Additionally, prefer the CLI to test your endpoint after deployment: middlebrick scan <url>. If you need continuous coverage in pipelines, the GitHub Action can add API security checks to your CI/CD pipeline and fail builds if risk scores drop below your threshold, while the Pro plan supports continuous monitoring and compliance mappings for frameworks such as OWASP API Top 10.

Frequently Asked Questions

Can request smuggling occur when mTLS is used if the frontend strips Transfer-Encoding?
Yes. If the frontend strips Transfer-Encoding but forwards a request that Actix interprets as chunked, or if the frontend normalizes differently than Actix, the boundary parsing can diverge. Always normalize headers identically on both sides and reject conflicting header combinations.
Does middleBrick fix smuggling issues found during scans?
middleBrick detects and reports findings with remediation guidance, but it does not fix, patch, or block issues. Use the findings and guidance to update your frontend/Actix header normalization and mTLS configuration, and consider the CLI or GitHub Action to integrate checks into your workflow.