Request Smuggling in Axum
Request Smuggling in Axum
use axum::{routing::get, Router, Request, response::IntoResponse};
use axum::http::{Method, StatusCode, HeaderMap};
use axum::body::Body;
use axum::extract::State;
// Example vulnerable endpoint
let app = Router::new()
.route("/api/v1/token", get(get_token))
.route("/api/v1/token", post(post_token))
.with_state(SharedState::new());
async fn get_token(Path(id): Path, State(state): State) -> impl IntoResponse {
// Direct use of header values without validation
let user_header = state.headers.get("X-Forwarded-For").cloned().unwrap_or("unknown".into());
let user_ip = extract_ip_from_header(&user_header);
// ... processing logic that trusts the header
(StatusCode::OK, user_ip)
}
async fn post_token(Path(id): Path, State(state): State, headers: HeaderMap, body: Body) -> impl IntoResponse {
// Axum reads the entire body into memory
let bytes = hyper::body::to_bytes(body).await.unwrap();
let payload = String::from_utf8(bytes.to_vec()).unwrap();
// ... logic that uses payload without proper size validation
(StatusCode::OK, "processed")
}
// Helper to extract IP (simplified)
async fn extract_ip_from_header(header: &Option) -> String {
header.as_ref().unwrap_or(&"".to_string())[..].to_string()
}
// Shared state holder
struct AppState {
headers: std::sync::Arc>,
}
impl AppState {
fn new() -> Self {
Self {
headers: std::sync::Arc::new(std::sync::Mutex::new(HeaderMap::new()))
}
}
}
In Axum (Rust web framework), request smuggling typically occurs when multiple HTTP parsers handle request boundaries inconsistently. Axum relies on Hyper for HTTP parsing, but vulnerabilities arise when upstream reverse proxies (like Cloudflare) or middleware interpret request framing differently. Classic smuggling patterns include Transfer-Encoding: chunked combined with Content-Length headers, or Content-Length vs. Content-Type ambiguity in POST requests.
Attackers can craft requests that appear valid to Axum but are split differently by a front-end proxy, causing the proxy to forward incomplete or misinterpreted requests to the backend. For example, sending a request with both Content-Length: 0 and a body that begins with 0
in a chunked encoding context can confuse parsers. Since Axum processes the request after the proxy has already consumed part of the stream, state inconsistency emerges. This is especially dangerous in APIs that expect JSON but receive malformed payloads due to boundary confusion.
Detection requires examining how requests are parsed at multiple layers. Axum's security posture improves when paired with strict proxy configuration, but the framework itself does not enforce proxy-aware parsing. Developers must audit header handling and avoid relying on single-layer validation. Tools like middleBrick can scan Axum endpoints for smuggling indicators by testing how malformed requests are handled across multiple HTTP hops.
FAQ
Q: Can request smuggling be exploited in Axum without TLS termination at the proxy?
A: Yes. Even when Axum runs directly behind TLS termination, smuggling can occur if the TLS layer is terminated before request parsing, and headers like Transfer-Encoding or Content-Length are misinterpreted by intermediate layers. The vulnerability exists at the HTTP parsing boundary, regardless of encryption.
Q: Is request smuggling covered under OWASP API Top 10?
A: Yes. It maps to API-Security Top 10 under Broken Object Level Authorization and Mass Assignment, but more precisely aligns with API Request Smuggling as a transport-layer issue that enables other attacks like BOLA or injection.