Crlf Injection in Axum with Jwt Tokens
Crlf Injection in Axum with Jwt Tokens
Crlf Injection occurs when an attacker can inject carriage return (CR, \r) and line feed (\n) characters into HTTP headers or cookies, causing header splitting and potential response splitting. In Axum, this risk is amplified when JWT tokens are handled improperly in request processing pipelines, especially when token values or claims are reflected into HTTP headers or cookies without sanitization.
Consider an Axum handler that reads a JWT from an Authorization header and uses its payload to set a custom response header or cookie. If the JWT or a claim derived from it is concatenated directly into a header value without validation, an attacker can supply a token containing \r\n sequences. These sequences can inject additional headers, such as Set-Cookie, or break the header block, leading to HTTP response splitting, cache poisoning, or cross-site scripting when the manipulated response is served to other users.
For example, if an application decodes a JWT and uses its subject claim to set a X-User-ID header, a token with subject "attacker\r\nSet-Cookie: session=hijacked" will cause Axum to treat the injected \r\n as a header delimiter. Because Axum does not inherently sanitize inputs that feed into header construction, the injected header is emitted, potentially enabling session fixation or information disclosure. This becomes particularly dangerous when combined with other vulnerabilities, such as insufficient input validation or missing integrity checks on JWTs.
In the context of middleware, if a JWT is passed through multiple layers and later used to construct headers, logs, or cookies, any unchecked reflection point can become a vector. Attackers may also exploit this to bypass intended routing or security policies by smuggling malicious headers past upstream protections. Real-world attack patterns include using \r\n to inject Content-Security-Policy modifications or to forge authentication-related cookies that persist beyond the intended scope.
Because JWT tokens often carry sensitive identity information, their improper handling in Axum can lead to more severe outcomes when combined with Crlf Injection. An attacker who can control the token payload might escalate the impact by injecting headers that influence downstream systems, such as proxies or caching layers. This underscores the importance of validating and sanitizing any user-controlled data that participates in HTTP message construction, including claims extracted from JWTs.
Jwt Tokens-Specific Remediation in Axum
To remediate Crlf Injection risks when working with JWT tokens in Axum, ensure that any data derived from JWT claims is strictly validated and sanitized before being used in HTTP headers, cookies, or other message components. Avoid directly concatenating token payloads into header values. Instead, use Axum's typed extractors and response builders, which help maintain separation between message structure and dynamic content.
One approach is to enforce allowlists on claims that influence headers or cookies, rejecting tokens that contain unexpected or malformed characters such as CR or LF. You can validate the subject or other identifier claims to ensure they conform to a safe pattern before using them in routing or header logic.
Below are concrete Axum examples that demonstrate secure handling of JWT tokens. The first example shows how to extract and validate a JWT payload without exposing header injection surfaces:
use axum::{routing::get, Router, http::HeaderMap};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String,
// other claims
}
async fn handler(
headers: HeaderMap,
) -> Result {
let auth = headers.get("authorization")
.and_then(|v| v.to_str().ok())
.ok_or((axum::http::StatusCode::BAD_REQUEST, "Missing authorization header".into()))?;
let token = auth.strip_prefix("Bearer ")
.ok_or((axum::http::StatusCode::BAD_REQUEST, "Invalid authorization format".into()))?;
let validation = Validation::new(Algorithm::HS256);
let token_data = decode::(token, &DecodingKey::from_secret("secret".as_ref()), &validation)
.map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "Invalid token".into()))?;
let subject = &token_data.claims.sub;
if subject.chars().any(|c| c == '\r' || c == '\n') {
return Err((axum::http::StatusCode::BAD_REQUEST, "Invalid subject".into()));
}
Ok(format!("User: {}", subject))
}
fn app() -> Router {
Router::new().route("/user", get(handler))
}
The second example demonstrates setting a custom header safely by sanitizing the claim and avoiding direct injection:
use axum::{routing::get, Router, http::HeaderMap, response::IntoResponse};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String,
}
async fn handler(
headers: HeaderMap,
) -> Result {
let auth = headers.get("authorization")
.and_then(|v| v.to_str().ok())
.ok_or((axum::http::StatusCode::BAD_REQUEST, "Missing authorization header".into()))?;
let token = auth.strip_prefix("Bearer ")
.ok_or((axum::http::StatusCode::BAD_REQUEST, "Invalid authorization format".into()))?;
let validation = Validation::new(Algorithm::HS256);
let token_data = decode::(token, &DecodingKey::from_secret("secret".as_ref()), &validation)
.map_err(|_| (axum::http::StatusCode::UNAUTHORIZED, "Invalid token".into()))?;
let subject = &token_data.claims.sub;
if subject.chars().any(|c| c == '\r' || c == '\n') {
return Err((axum::http::StatusCode::BAD_REQUEST, "Invalid subject".into()));
}
let mut response = (axum::http::StatusCode::OK, "OK".into_response());
response.headers_mut().insert("X-User-Id", subject.parse().map_err(|_| (axum::http::StatusCode::BAD_REQUEST, "Invalid header value".into()))?);
Ok(response)
}
These patterns ensure that JWT-derived values are validated for disallowed control characters before being used in header construction, reducing the risk of Crlf Injection. Regular security scans using tools like the middleBrick CLI can help detect such issues in your Axum services by analyzing endpoints that process JWTs without adequate input checks.