HIGH format stringaxumjwt tokens

Format String in Axum with Jwt Tokens

Format String in Axum with Jwt Tokens — how this specific combination creates or exposes the vulnerability

A format string vulnerability occurs when user-controlled input is passed directly into a formatting function such as format! or write! without explicit format specifiers. In Axum, this can arise when building error messages, log lines, or dynamic responses that incorporate JWT token data, claims, or headers. If an attacker can influence the string passed to formatting routines—for example, a JWT claim like sub or a custom header value—and that input is used in a logging or response path with an unchecked format string, the application may read from or write to memory based on the contents of the attacker-controlled token.

Consider an Axum handler that logs a JWT payload using a user-supplied field in the format string:

let token_claim = user_input; // e.g., from a JWT claim
let log_message = format!("Token subject: {}", token_claim);
tracing::info!("{}", log_message);

If user_input contains format specifiers such as %s, %x, or %n, Rust’s format! macro will interpret them, potentially causing memory reads or writes. This can lead to information disclosure (reading stack memory via %s or %p) or even arbitrary code execution in more severe cases (via %n). When JWT tokens are parsed and their claims are forwarded into logging or response construction without sanitization, the token data becomes an attack vector.

In a real-world scenario, an attacker might supply a malicious JWT with a crafted claim like { "sub": "%s%s%s%s" }. If the application logs this claim using an uncontrolled format string, the handler may inadvertently leak stack contents. Because Axum commonly deserializes JWTs into claims structures, developers may mistakenly believe that the data is safe after validation, but the risk shifts to how that data is used afterward—especially in error reporting or telemetry where format strings are dynamically built.

Moreover, if Axum middleware or custom extractors construct messages using user data from JWTs with unchecked formatting, the vulnerability can persist across multiple layers. For instance, using format_args! in a logging macro that includes a JWT header value can trigger the same issue. The key factor is not the presence of JWT tokens themselves, but whether token-derived data is embedded into format strings without strict control over the format specifiers.

Jwt Tokens-Specific Remediation in Axum — concrete code fixes

To prevent format string issues when working with JWT tokens in Axum, ensure that all token-derived data is treated as opaque values and never directly interpolated into format strings. Use explicit format specifiers and avoid passing user-influenced data as the format string itself.

Safe logging with explicit specifiers: Always use a known-safe format string on the left side of the format macro and pass token data as arguments.

use axum::{routing::get, Router};
use tracing::info;

async fn handler(token_sub: String) -> String {
    // Safe: format string is a literal, token data is an argument
    info!(target: "auth", "Token subject: {}", token_sub);
    format!("OK")
}

Avoid dynamic format strings with token data: Never construct the format string from JWT claims or headers.

// UNSAFE: do not do this
let user_format = user_supplied_string; // could contain %s, %n, etc.
let message = format!(user_format, some_data); // format string vulnerability

// SAFE: use a fixed format string
let message = format!("Data: {}", some_data);

Sanitizing JWT claims before use: If you need to include JWT claims in structured output (e.g., JSON responses), serialize them directly without string interpolation that could trigger formatting issues.

use axum::Json;
use serde_json::json;

async fn claims_handler(claims: Json) -> Json {
    // Safe: build JSON object without format string interpolation
    Json(json!({
        "sub": claims.get("sub").and_then(|v| v.as_str()).unwrap_or("unknown"),
        "iss": claims.get("iss").and_then(|v| v.as_str()).unwrap_or("unknown")
    }))
}

For CLI and CI/CD integration, you can use the middleBrick CLI to scan your Axum endpoints for such issues: middlebrick scan <url>. Teams using the Pro plan can enable continuous monitoring to detect regressions, and the GitHub Action can fail builds if security scores drop below a chosen threshold.

Frequently Asked Questions

Can a JWT token's contents ever be safe to include in a format string?
No. Treat all JWT token data as untrusted input. Even if the token is signed, its claims should never be used as a format string or directly interpolated in logging or response construction without explicit, fixed format specifiers.
Does middleBrick detect format string vulnerabilities during JWT-related scans?
middleBrick runs 12 parallel security checks including input validation and unsafe consumption patterns. While it identifies indicators that may point to formatting risks, it reports findings with severity and remediation guidance rather than fixing the code.