HIGH request smugglingaxum

Request Smuggling in Axum

How Request Smuggling Manifests in Axum

Request smuggling in Axum typically occurs when multiple HTTP parsers disagree on request boundaries. This happens when Axum's HTTP request parsing conflicts with a reverse proxy or load balancer sitting in front of it. The vulnerability arises from ambiguous Content-Length and Transfer-Encoding headers that can be interpreted differently by Axum versus upstream components.

In Axum applications, request smuggling often manifests through specific code patterns. Consider an Axum route handler that processes multipart form data:

use axum::extract::{Multipart, Form};

async fn upload(mut multipart: Multipart) -> String {
    while let Some(field) = multipart.next_field().await.unwrap() {
        let name = field.name().unwrap();
        let data = field.bytes().await.unwrap();
        // Process field data
    }
    "Upload complete".to_string()
}

let app = Router::new()
    .route("/upload", post(upload));

The vulnerability occurs when Axum parses the multipart body differently than the upstream proxy. An attacker can craft requests with conflicting Content-Length and Transfer-Encoding headers, causing Axum to process a different request boundary than what the proxy expects. This can lead to request smuggling where one malicious request gets concatenated with a victim's legitimate request.

Another Axum-specific manifestation involves streaming responses. When using Axum's Response::stream or StreamBody, improper handling of chunked transfer encoding can create smuggling opportunities:

use axum::body::StreamBody;
use tokio::fs::File;
use tokio_util::io::ReaderStream;

async fn download() -> StreamBody {
    let file = File::open("large_file.dat").await.unwrap();
    StreamBody::new(file)
}

let app = Router::new()
    .route("/download", get(download));

If the upstream proxy doesn't properly handle chunked encoding while Axum does, an attacker can manipulate chunk sizes to smuggle requests across the boundary.

Axum-Specific Detection

Detecting request smuggling in Axum requires understanding both the application code and the deployment infrastructure. Start by examining how Axum parses HTTP requests and how it handles different content encodings. The key is identifying where Axum's parser might disagree with upstream components.

Code analysis should focus on these Axum-specific patterns:

use axum::extract::RawBody;

async fn raw_handler(body: RawBody) -> String {
    let bytes = body.bytes().await.unwrap();
    // Raw body access without proper validation
    String::from_utf8_lossy(&bytes).to_string()
}

Routes that accept RawBody or directly access the request stream are particularly vulnerable because they bypass Axum's built-in request validation.

For automated detection, middleBrick's black-box scanning approach is particularly effective for Axum applications. Since middleBrick tests the unauthenticated attack surface without requiring credentials or access to source code, it can identify request smuggling vulnerabilities by:

  • Sending requests with conflicting Content-Length and Transfer-Encoding headers
  • Testing various chunk size manipulations in chunked encoding
  • Analyzing how the server responds to malformed HTTP requests
  • Checking for discrepancies between expected and actual request processing

middleBrick's LLM/AI security module also helps detect if your Axum application has AI endpoints that might be vulnerable to prompt injection through smuggled requests. The scanner tests 27 regex patterns for system prompt leakage and performs active prompt injection testing across AI endpoints.

During scanning, middleBrick provides a security risk score (A–F) with specific findings about request smuggling vulnerabilities, including severity levels and remediation guidance. The scanner tests your Axum API in parallel across 12 security categories, ensuring comprehensive coverage of potential smuggling vectors.

Axum-Specific Remediation

Remediating request smuggling in Axum applications requires both code-level fixes and deployment configuration. Start with the application code by ensuring consistent request parsing and validation.

First, configure Axum to use strict HTTP parsing:

use axum::http::StatusCode;
use axum::response::IntoResponse;

async fn strict_handler() -> Result<impl IntoResponse, StatusCode> {
    // Enforce strict content-length validation
    Ok("Valid request")
}

let app = Router::new()
    .route("/strict", post(strict_handler))
    .with_state(AppState::new())
    .http1_only(); // Disable HTTP/2 if not needed

The http1_only() configuration ensures Axum doesn't attempt to negotiate HTTP/2, which can introduce additional parsing ambiguities.

For multipart form handling, add explicit validation:

use axum::extract::{Multipart, TypedHeader};
use axum::http::header::CONTENT_TYPE;

async fn safe_upload(
    TypedHeader(content_type): TypedHeader<CONTENT_TYPE>,
    mut multipart: Multipart,
) -> String {
    // Validate content type before processing
    if !content_type.as_str().starts_with("multipart/form-data") {
        return "Invalid content type".to_string();
    }
    
    while let Some(field) = multipart.next_field().await.unwrap() {
        let name = field.name().unwrap();
        let data = field.bytes().await.unwrap();
        // Process with size limits and validation
    }
    "Upload complete".to_string()
}

Implement strict content-length validation middleware:

use axum::middleware::Next;
use axum::response::IntoResponse;
use axum::http::{Request, StatusCode};

async fn content_length_middleware(
    mut req: Request,
    next: Next,
) -> impl IntoResponse {
    if let Some(len) = req.headers().get("content-length") {
        if let Ok(len) = len.to_str().parse::() {
            // Check against maximum allowed size
            if len > 1_000_000 { // 1MB limit
                return StatusCode::PAYLOAD_TOO_LARGE;
            }
        }
    }
    next.run(req).await
}

For deployment, ensure your reverse proxy and Axum application use consistent HTTP parsing. Configure your proxy to remove ambiguous headers before forwarding to Axum:

# Nginx configuration example
proxy_hide_header Transfer-Encoding;
proxy_set_header Content-Length "";
proxy_pass http://axum_backend;

Consider using middleBrick's continuous monitoring (Pro plan) to regularly scan your Axum API endpoints. This ensures new routes or changes don't reintroduce smuggling vulnerabilities. The scanner's 5–15 second scan time makes it practical to integrate into your development workflow.

Frequently Asked Questions

How can I test my Axum application for request smuggling vulnerabilities?
Use middleBrick's black-box scanning to test your Axum API endpoints. The scanner sends requests with conflicting Content-Length and Transfer-Encoding headers, tests chunk size manipulations, and analyzes how your server responds. middleBrick provides a security risk score with specific findings about request smuggling vulnerabilities, including severity levels and remediation guidance. No credentials or source code access required—just submit your API URL.
Does Axum have built-in protections against request smuggling?
Axum provides basic HTTP/1.1 request parsing but doesn't include comprehensive request smuggling protections by default. You need to implement additional safeguards such as strict content-length validation, content-type verification for multipart forms, and middleware to validate request headers. Also ensure your deployment configuration (reverse proxy settings) is consistent with Axum's parsing behavior. middleBrick can help identify where your Axum application needs additional protections.