Crlf Injection in Axum with Api Keys
Crlf Injection in Axum with Api Keys — how this specific combination creates or exposes the vulnerability
Crlf Injection occurs when user-controlled input containing carriage return (CR, \r) and line feed (\n) characters is reflected into HTTP headers without validation. In Axum, this typically happens when API keys or other header-derived values are used to build downstream HTTP requests or are echoed into custom response headers. Axum does not automatically sanitize header values, so if an API key or a header derived from it is concatenated into a header string and forwarded, an attacker can inject extra headers or split the response.
Consider an Axum handler that accepts an API key via the Authorization header, extracts a tenant identifier, and forwards requests to an internal service. If the tenant identifier is reflected in a custom header such as X-Tenant without removing CR/LF characters, an attacker can craft a malicious API key that contains %0d%0a (URL-encoded CRLF) to inject headers like X-Internal: true or to perform HTTP response splitting. For example, an API key like valid_key%0d%0aX-Internal: true results in a forwarded request that includes an additional header, potentially bypassing authorization checks or causing the upstream service to misinterpret the message boundaries.
This combination is particularly risky when the Axum service acts as a proxy or gateway, because the injected headers may be processed by downstream components that trust the originating service. Even when the API key is validated against a database, the reflection path often occurs after validation, in logging, tracing, or forwarding logic. The risk is amplified if the Axum application uses the API key to construct URLs or headers for outbound calls, as CRLF characters can break header formatting and enable injection of new headers, trailer fields, or even a second request within the same TCP connection (HTTP request smuggling). Standard web frameworks may hide some of these risks, but Axum gives developers fine-grained control, which means the responsibility to sanitize and validate header values lies explicitly with the developer.
In practice, an attacker might send a request with an API key containing characters such as %0d%0aSet-Cookie: to inject a cookie, or %0d%0aContent-Length: to manipulate chunked encoding interpretations. Because the attack leverages trusted internal logic (API key validation plus header forwarding), the malicious request may appear legitimate to simple access controls. The injected headers can lead to information leakage, cache poisoning, or in more complex scenarios, facilitate request smuggling when combined with certain server and proxy configurations.
middleBrick detects such patterns as part of its Input Validation and Property Authorization checks, highlighting where user-controlled data reaches headers without proper sanitization. The scanner does not make assumptions about framework-specific escaping, so it flags concatenation patterns that could allow CRLF sequences in header contexts, including when API keys are used in outbound request construction. Developers should treat API keys and any derived header values as untrusted input and apply strict filtering before using them in any header-forming operation.
Api Keys-Specific Remediation in Axum — concrete code fixes
Remediation focuses on ensuring that API key values and any data derived from them are never directly reflected into HTTP headers without rigorous sanitization. In Axum, this means validating and transforming header inputs before using them in outbound requests or response construction. The following examples demonstrate safe patterns.
1) Reject or sanitize API keys before use. If the API key must be forwarded, strip or encode control characters. For instance, remove any CR or LF characters from extracted values:
use axum::{routing::get, Router, http::HeaderMap, extract::HeaderMapExt};fn sanitize_header_value(value: &str) -> String { value.chars().filter(|&c| c != '\r' && c != '\n').collect()}
Use this sanitizer on any variable that originates from headers, query parameters, or the API key before it is placed into a new header:
async fn handler(
headers: HeaderMap,
) -> Result<impl IntoResponse, (StatusCode, String)> { let api_key = headers.get("Authorization") .and_then(|v| v.to_str().ok()) .unwrap_or("");
// Example: derive a tenant identifier safely
let tenant = sanitize_header_value(&extract_tenant(api_key));
// Use tenant in a header for an outbound request
let mut req_builder = http::Request::builder() .header("X-Tenant", tenant);
// ... build and send request
Ok(StatusCode::OK)
}
2) Avoid using API-key-derived values in header names or in contexts where CRLF can split messages. When constructing outbound requests, prefer strongly typed headers or constants rather than string concatenation. For example, instead of building headers via string interpolation, use dedicated builder methods that do not accept raw newlines:
let request = http::Request::builder() .header("X-Tenant", "tenant123") // constant or sanitized value .body(body)?;
3) If you must log or store API key-related metadata, ensure that logging utilities do not inadvertently echo raw headers. Configure logging to redact sensitive header values and avoid writing raw user input into logs where CRLF injection could affect log parsing.
4) Apply framework-level filters or middleware that reject requests containing suspicious sequences in headers. While Axum does not provide built-in CRLF stripping, you can implement a validation layer that checks for \r and \n in critical inputs and returns a 400 response when detected.
These practices reduce the risk of header injection by ensuring that any data originating from API keys or headers is normalized before being used in header construction, aligning with secure handling of untrusted input in web frameworks.