HIGH header injectionaxum

Header Injection in Axum

How Header Injection Manifests in Axum

Header injection vulnerabilities in Axum typically occur when user-controlled input is incorporated into HTTP response headers without proper validation. Unlike traditional web frameworks where header injection might involve CRLF sequences, Axum's type-safe approach means the primary vectors are different.

The most common manifestation in Axum applications is through dynamic header construction using user input. For example, when building custom authentication headers, CORS configurations, or error responses that include user-provided data. Consider this vulnerable pattern:

async fn handle_request(
    Extension(db): Extension, 
    auth_header: Header<String>,
) -> impl IntoResponse {
    let token = auth_header.0.strip_prefix("Bearer ").unwrap_or_default();
    
    // Vulnerable: token directly used in header value
    let user_id = db.validate_token(token).await.unwrap_or("unknown");
    let response = Json(UserProfile { user_id });
    
    // Header injection possible if token contains newlines
    let mut headers = HeaderMap::new();
    headers.insert("X-User-Id", HeaderValue::from_str(&user_id).unwrap());
    
    (headers, response)
}

The vulnerability becomes critical when the user input contains newline characters ( or ), allowing attackers to inject additional headers or manipulate the response structure. Axum's type safety prevents classic HTTP response splitting via CRLF injection, but header injection remains possible through improper HeaderValue construction.

Another Axum-specific pattern involves dynamic CORS header generation:

async fn cors_handler(
    Origin(origin): Origin,
) -> impl IntoResponse {
    // Vulnerable: origin directly used without validation
    let mut headers = HeaderMap::new();
    headers.insert("Access-Control-Allow-Origin", 
        HeaderValue::from_str(origin).unwrap());
    
    // Additional headers can be injected
    headers.insert("X-Custom-Header", 
        HeaderValue::from_str("<script>alert(1)</script>").unwrap());
    
    (headers, Json(Status::Ok))
}

Header injection in Axum also commonly occurs through error handling middleware that reflects user input in response headers. When exceptions occur, some applications include diagnostic information in custom headers without proper sanitization.

Axum-Specific Detection

Detecting header injection in Axum applications requires understanding both the framework's patterns and the specific attack vectors. Static analysis tools often miss Axum-specific vulnerabilities because they don't understand the framework's type system and middleware patterns.

Runtime detection with middleBrick is particularly effective for Axum applications. The scanner tests for header injection by attempting to inject newline characters and special sequences into various header inputs. Here's what middleBrick specifically looks for in Axum APIs:

middlebrick scan https://api.example.com/auth

The scanner tests common injection patterns including:

  • Newline character injection ( , ) in authorization headers
  • Header splitting attempts in custom header values
  • Cross-origin header manipulation attempts
  • Response splitting via malformed header sequences

For Axum specifically, middleBrick analyzes the framework's middleware chain to identify potential injection points. The scanner examines how headers are constructed throughout the request lifecycle, from initial parsing through middleware processing to final response generation.

Manual testing for header injection in Axum should include:

curl -H "Authorization: Bearer validtoken
X-Injected-Header: malicious-value" \
  https://api.example.com/protected

Watch for unexpected headers appearing in the response or changes in response behavior. Axum's strong typing means classic CRLF injection won't work, but improper HeaderValue construction can still lead to injection vulnerabilities.

middleBrick's LLM/AI security module also checks for header injection in AI-specific endpoints, testing for prompt injection through header manipulation in LLM APIs built with Axum.

Axum-Specific Remediation

Remediating header injection in Axum requires leveraging the framework's type safety while implementing proper input validation. The key is ensuring all user-controlled input is properly sanitized before being used in header construction.

The most effective approach uses Axum's HeaderValue::from_str with validation:

use axum::http::HeaderValue;
use regex::Regex;

const HEADER_REGEX: &'static str = r"^[\w\d\.\-]+$";

fn validate_header_value(input: &str) -> Result<HeaderValue, &'static str> {
    if input.contains('\n') || input.contains('\r') {
        return Err("Header contains newline characters");
    }
    
    // Validate against allowed pattern
    if !Regex::new(HEADER_REGEX).unwrap().is_match(input) {
        return Err("Header contains invalid characters");
    }
    
    HeaderValue::from_str(input).map_err(|_| "Invalid header value")
}

async fn secure_handler(
    auth_header: Header<String>,
) -> impl IntoResponse {
    let token = auth_header.0.strip_prefix("Bearer ").unwrap_or_default();
    
    // Validate token before using in headers
    let user_id = validate_header_value(&token)
        .unwrap_or_else(|_| HeaderValue::from_static("unknown"));
    
    let mut headers = HeaderMap::new();
    headers.insert("X-User-Id", user_id);
    
    (headers, Json(Status::Ok))
}

For CORS handling in Axum, implement a whitelist approach:

async fn cors_handler(
    Origin(origin): Origin,
) -> impl IntoResponse {
    let allowed_origins = ["https://example.com", "https://app.example.com"];
    
    let origin_str = origin.as_str();
    let is_allowed = allowed_origins.contains(&origin_str);
    
    let mut headers = HeaderMap::new();
    if is_allowed {
        headers.insert("Access-Control-Allow-Origin", 
            HeaderValue::from_str(origin_str).unwrap());
    }
    
    (headers, Json(Status::Ok))
}

Axum's middleware system provides excellent opportunities for centralized header validation:

use axum::middleware::Next;
use axum::http::{Request, Response};

async fn header_validation_middleware(
    mut req: Request<Body>,
    next: Next<Body>,
) -> Result<Response<Body>> {
    // Validate headers before processing
    for (name, value) in req.headers().iter() {
        if let Ok(value_str) = value.to_str() {
            if value_str.contains('\n') || value_str.contains('\r') {
                return Ok(Response::builder()
                    .status(400)
                    .body(Body::from("Invalid header"))
                    .unwrap());
            }
        }
    }
    
    next.run(req).await
}

let app = Router::new()
    .route("/api/secure", get(secure_handler))
    .layer(header_validation_middleware);

Using Axum's type system effectively prevents many injection vectors. The Header<T> extractor ensures type safety, while proper validation of HeaderValue construction prevents injection through malformed inputs.

Frequently Asked Questions

Can Axum's type safety prevent all header injection attacks?
No, Axum's type safety prevents classic HTTP response splitting via CRLF injection, but header injection remains possible through improper HeaderValue construction and dynamic header generation using user input. Developers must still validate and sanitize all user-controlled input used in headers.
How does middleBrick scan for header injection in Axum applications?
middleBrick tests for header injection by attempting to inject newline characters and special sequences into various header inputs. The scanner examines how headers are constructed throughout the request lifecycle and tests common injection patterns including newline character injection, header splitting attempts, and cross-origin header manipulation.