HIGH header injectionactix

Header Injection in Actix

How Header Injection Manifests in Actix

Header injection vulnerabilities in Actix applications typically occur when user-controlled input flows into HTTP response headers without proper validation. In Actix, this often manifests through the HttpResponse::insert_header method or the add_header extension method, where dynamic values from request parameters, query strings, or JSON payloads are directly inserted into response headers.

A common Actix-specific pattern that leads to header injection involves extracting values from the request body or query parameters and using them as header values. For example:

async fn echo_header(req: HttpRequest) -> HttpResponse { 
    let header_name = req.query_string() 
        .split('=') 
        .next() 
        .unwrap_or("X-Custom");
    
    HttpResponse::Ok()
        .insert_header((header_name, "injected-value"))
        .finish()
}

This code is vulnerable because an attacker can control the header name through the query string, potentially injecting malicious headers like X-Forwarded-Host or Location for open redirect attacks. The vulnerability becomes more severe when combined with Actix's header normalization, which automatically lowercases header names, making it easier to bypass simple allowlist checks.

Another Actix-specific manifestation occurs when using the HttpResponseBuilder with dynamic content. Developers might extract values from JSON payloads and directly use them in headers:

async fn create_response(json: web::Json<MyData>) -> HttpResponse {
    let custom_header = json.header_name.clone();
    let custom_value = json.header_value.clone();
    
    HttpResponse::Ok()
        .insert_header((custom_header, custom_value))
        .finish()
}

The danger here is that both the header name and value are user-controlled, allowing for CRLF injection attacks where an attacker can insert newline characters to create additional headers or modify the response structure entirely.

Actix-Specific Detection

Detecting header injection in Actix applications requires examining how user input flows into header construction. The most effective approach is static code analysis combined with runtime testing. Using middleBrick's API security scanner, you can identify header injection vulnerabilities by scanning your Actix endpoints with the command:

npx middlebrick scan http://localhost:8080/api/endpoint

middleBrick tests for header injection by sending payloads containing CRLF sequences (%0A%0D) and observing if the response contains unexpected headers. The scanner specifically looks for Actix's insert_header and add_header usage patterns where the header name or value originates from request data.

For manual detection in Actix codebases, search for these patterns:

grep -r "insert_header" . | grep -E "(req\.|query\(|json\.|form\()"
grep -r "add_header" . | grep -E "(req\.|query\(|json\.|form\()"

Pay special attention to Actix's web::Query, web::Json, and web::Form extractors, as these are common sources of user-controlled data that might flow into headers. The scanner also checks for Actix's HttpResponse::default combined with dynamic header setting, which is another indicator of potential injection points.

middleBrick's LLM security checks are particularly relevant for Actix applications using AI features, as header injection can be used to manipulate system prompts or extract sensitive information from AI responses. The scanner tests for 27 regex patterns that detect system prompt leakage through header manipulation.

Actix-Specific Remediation

Remediating header injection in Actix requires a defense-in-depth approach. The most effective strategy is to implement strict allowlists for header names and values. Actix provides several mechanisms for safe header handling:

use actix_web::{http::header, HttpResponse};

async fn safe_response(req: HttpRequest) -> HttpResponse {
    let safe_headers = vec!["x-custom", "x-request-id"];
    let header_name = req.query_string()
        .split('=')
        .next()
        .unwrap_or("x-custom");
    
    // Validate header name against allowlist
    if !safe_headers.contains(&header_name) {
        return HttpResponse::BadRequest()
            .body("Invalid header name");
    }
    
    // Validate and sanitize header value
    let header_value = req.query_string()
        .split('=')
        .nth(1)
        .unwrap_or_default();
    
    // Remove CRLF characters
    let sanitized_value = header_value.replace(["\r", "\n"], "");
    
    HttpResponse::Ok()
        .insert_header((header_name, sanitized_value))
        .finish()
}

For Actix applications that need to handle dynamic headers, use the header::IntoHeaderValue trait to ensure values are properly encoded:

use actix_web::{http::header, HttpResponse};

async fn dynamic_headers(json: web::Json<MyData>) -> HttpResponse {
    let header_name = json.header_name.clone();
    let header_value = json.header_value.clone();
    
    // Validate header name format
    if !header_name.chars().all(|c| c.is_alphanumeric() || c == '-') {
        return HttpResponse::BadRequest()
            .body("Invalid header name format");
    }
    
    // Create safe header value
    let safe_value = match header::HeaderValue::from_str(&header_value) {
        Ok(value) => value,
        Err(_) => return HttpResponse::BadRequest()
            .body("Invalid header value"),
    };
    
    HttpResponse::Ok()
        .insert_header((header_name, safe_value))
        .finish()
}

For Actix applications using middleware, implement header validation at the middleware level to catch injection attempts before they reach handlers:

use actix_web::{dev::ServiceRequest, dev::ServiceResponse, middleware::Transform};
use futures_util::future::{ready, Ready};

struct HeaderValidation;

impl<S, B> Transform<S> for HeaderValidation
where
    S: actix_web::dev::Service<Request = ServiceRequest, Response = ServiceResponse<B>>,
    S::Future: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type InitError = ();
    type Transform = HeaderValidationMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ready(Ok(HeaderValidationMiddleware { service }))
    }
}

struct HeaderValidationMiddleware<S> {
    service: S,
}

impl<S, B> actix_web::dev::Service for HeaderValidationMiddleware<S>
where
    S: actix_web::dev::Service<Request = ServiceRequest, Response = ServiceResponse<B>>,
    S::Future: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = S::Error;
    type Future = S::Future;

    fn poll_ready(
        &mut self,
        cx: &mut std::task::Context,
    ) -> std::task::Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&mut self, req: ServiceRequest) -> Self::Future {
        // Check for suspicious header patterns
        if let Some(headers) = req.headers().get("X-Custom") {
            if headers.to_string().contains(["\r", "\n"]) {
                // Block request with suspicious headers
                return ready(Err(actix_web::error::ErrorBadRequest(
                    "Suspicious header content detected",
                )));
            }
        }
        self.service.call(req)
    }
}

This middleware validates headers before they reach your application logic, providing an additional layer of protection against header injection attacks in Actix applications.

Frequently Asked Questions

How can I test my Actix application for header injection vulnerabilities?
Use middleBrick's API security scanner by running npx middlebrick scan <your-actix-endpoint>. The scanner tests for header injection by sending payloads with CRLF sequences and checking if they result in unexpected headers or response modifications. You can also manually test by sending requests with %0A%0D sequences in query parameters and observing the response headers.
What's the difference between header injection and HTTP response splitting?
Header injection is the broader category where user input flows into HTTP headers. HTTP response splitting is a specific type of header injection attack that uses CRLF sequences to split the response and inject new headers or create additional responses. In Actix, both vulnerabilities manifest similarly but response splitting is more severe as it can lead to cache poisoning and XSS attacks.