Http Request Smuggling in Axum with Jwt Tokens
Http Request Smuggling in Axum with Jwt Tokens — how this specific combination creates or exposes the vulnerability
HTTP request smuggling arises when an API processes requests differently depending on whether a request is considered trusted (frontend) versus untrusted (origin). In Axum applications that rely on JWT tokens for authentication, this mismatch can expose smuggling opportunities even when tokens are validated. The vulnerability is not in JWT verification itself, but in how Axum middleware ordering and request transformations interact with parsers for body formats such as JSON or form data.
Consider an Axum service that uses tower-http for compressed requests and also validates JWTs via a custom middleware or jsonwebtoken crate. If the service enables request body reading before JWT validation and also allows header manipulation or content-length/transfer-encoding parsing to diverge, an attacker can craft two requests that arrive differently at the framework layer versus the application layer. For example, an attacker may send one request with Content-Length: 50 and another with Transfer-Encoding: chunked in a pipeline, causing the front-end parser to interpret the body one way and the application parser another. If JWT validation occurs after body parsing or shares mutable state with parsers, the boundary between these interpretations can be abused to bypass intended routing or access controls.
In Axum, this often maps to the twelve parallel security checks. The BOLA/IDOR and Property Authorization checks are especially relevant: if request smuggling alters which resource identifiers are evaluated or which properties are considered authorized, an attacker can access or modify other users’ data. Input Validation and Unsafe Consumption checks also apply, because malformed bodies or inconsistent parsing can lead to unexpected deserialization behavior. Even without authentication bypass, smuggling can change the effective API surface by causing one route to process a request intended for another, which may expose sensitive operations encoded in JWT claims or misinterpreted by downstream handlers.
Real-world patterns include mismatched handling of Transfer-Encoding and Content-Length when middleware modifies the request before routing, or when body extractors run before JWT validation, allowing an attacker to smuggle a request so that the JWT applies to a different operation than the one executed. To detect this, middleBrick runs parallel checks that compare runtime behavior against OpenAPI/Swagger specs (including $ref resolution) and unauthentinated attack surface testing, identifying discrepancies between declared security schemes and actual routing behavior in Axum services that use JWT tokens.
Jwt Tokens-Specific Remediation in Axum — concrete code fixes
Remediation focuses on strict ordering, canonical request normalization, and avoiding shared mutable state between parsing and authentication. In Axum, validate JWTs before body extraction and ensure the request representation seen by authentication cannot be altered by downstream parsing. Use tower-http middleware to normalize headers and reject ambiguous encodings early.
Example: Validate JWT before body parsing
Structure your routes so that JWT validation occurs in a layer that runs before any JSON or form extractors. This prevents an attacker from smuggling a request that changes how the body is interpreted after authentication.
use axum::{
async_trait,
extract::FromRequest,
response::IntoResponse,
routing::post,
Router,
};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation, TokenData};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Claims {
sub: String,
exp: usize,
}
struct JwtExtractor {
token: String,
}
#[async_trait]
impl FromRequest for JwtExtractor {
type Rejection = (axum::http::StatusCode, String);
async fn from_request(req: axum::http::Request<axum::body::Body>) -> Result {
let auth_header = req.headers()
.get("authorization")
.and_then(|v| v.to_str().ok())
.ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing authorization header".to_string()))?
.strip_prefix("Bearer ")
.ok_or((axum::http::StatusCode::UNAUTHORIZED, "Invalid authorization format".to_string()))?
.to_string();
let token_data = decode::
Canonicalize headers and reject ambiguous encodings
Use tower-http to normalize Content-Length and Transfer-Encoding before routing. This reduces the risk that an attacker can exploit differences between frontend and backend parsers.
use tower_http::normalize_path::NormalizePath;
use tower_http::set_header::SetResponseHeaderLayer;
use tower_http::trace::TraceLayer;
let app = Router::new()
.route("/submit", post(handler))
.layer(NormalizePath::trim()) // canonical path
.layer(SetResponseHeaderLayer::overriding(
"X-Content-Type-Options",
"nosniff",
))
.layer(TraceLayer::new_for_http());
Enforce strict content-type and body size limits
Configure extractors to reject unexpected content types and limit body size so that smuggling attempts that rely on oversized or malformed bodies are rejected early.
use axum::extract::DefaultBodyLimit;
let app = Router::new()
.route("/submit", post(handler))
.layer(DefaultBodyLimit::max(1024 * 1024)); // 1 MB
By validating JWTs before body extraction, canonicalizing headers, and enforcing strict limits, you reduce the attack surface for request smuggling in Axum services that use JWT tokens. These practices align with the checks performed by middleBrick, including BOLA/IDOR, Property Authorization, and Input Validation assessments.