Integer Overflow in Axum with Mutual Tls
Integer Overflow in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability
An integer overflow in an Axum service that uses Mutual TLS (mTLS) can arise when a numeric value derived from a client-supplied header or payload—such as a Content-Length, message counter, or rate-limit token—is stored in a fixed-size integer type (e.g., u16 or u32) and later used in arithmetic like buffer sizing or loop bounds. If the input is not validated, an attacker can supply a value that wraps around at the type boundary, producing a small number that leads to undersized buffers or incorrect iterations. In the presence of mTLS, the overflow may be reachable only after successful client certificate verification, which can create a false sense of security: authentication is enforced, but the authenticated request still triggers unsafe arithmetic. For example, an Axum extractor that parses a u16 message length from a header and then allocates a Vec
Mutual Tls-Specific Remediation in Axum — concrete code fixes
To mitigate integer overflow in Axum with mTLS, combine rigorous input validation, safe arithmetic, and secure mTLS configuration. Use saturating arithmetic (e.g., .saturating_add), checked conversions (e.g., u32::try_from), and limits that reflect protocol constraints rather than trusting authenticated client values. For mTLS in Axum, enforce certificate verification via hyper::server::conn::AddrStream and tower::service_fn with a custom validator, or use axum::extract::connect_info to inspect the peer certificate when using hyper with rustls. Below are concrete, working examples of Axum handlers that apply both safe integer handling and mTLS checks.
use axum::{
async_trait,
extract::connect_info::ConnectInfo,
routing::post,
Router,
};
use hyper::{
body::Bytes,
server::conn::AddrStream,
service::service_fn,
Request, Response, StatusCode,
};
use rustls::{Certificate, ServerConfig};
use std::net::SocketAddr;
use std::sync::Arc;
// Safe integer handling: validate and convert with checks.
async fn handle_message(
ConnectInfo(addr_stream): ConnectInfo,
bytes: Bytes,
) -> Result {
// Verify client certificate is present and valid (pseudocode for illustration).
if !peer_cert_ok(addr_stream) {
return Err((StatusCode::FORBIDDEN, "invalid client cert".into()));
}
// Assume first 4 bytes represent a length field sent by the client.
if bytes.len() < 4 {
return Err((StatusCode::BAD_REQUEST, "missing length".into()));
}
let len_bytes: [u8; 4] = bytes[..4].try_into().map_err(|_| (StatusCode::BAD_REQUEST, "invalid length".into()))?;
let len = u32::from_be_bytes(len_bytes);
// Validate length before any allocation or arithmetic.
const MAX_MSG: u32 = 1024 * 1024; // 1 MiB
if len == 0 || len > MAX_MSG {
return Err((StatusCode::LENGTH_REQUIRED, "length out of bounds".into()));
}
// Use saturating arithmetic to avoid overflow in further calculations.
let header_size = 4u32.saturating_add(len);
// Further processing with safe conversions...
Ok(format!("processed message of length {}", len))
}
// Pseudo-check: in practice, inspect the peer certs via rustls connection state.
fn peer_cert_ok(_: &AddrStream) -> bool {
// Real implementation would extract and verify certificate chain.
true
}
#[tokio::main]
async fn main() {
// Minimal example: mTLS setup is typically done in hyper + rustls.
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let app = Router::new().route("/message", post(handle_message));
// In production, configure ServerConfig with client authentication.
let config = Arc::new(ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth() // Replace with client_auth for mTLS
.with_single_cert(vec![], rustls::PrivateKey(vec![]))
.unwrap());
println("Listening on https://{}", addr);
// hyper server with rustls and Axum integration would start here.
}
In this example, the handler extracts a length field from the request body and validates it before any allocation. It uses saturating arithmetic and explicit bounds checks to prevent integer overflow. The mTLS check is represented by peer_cert_ok, which in a real deployment would validate the client certificate extracted from the connection. By combining these practices, you ensure that authenticated requests remain safe from numeric confusion and overflow attacks.