HIGH format stringaxumapi keys

Format String in Axum with Api Keys

Format String in Axum with Api Keys — how this 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 specification. In Axum, this risk can manifest when API keys or other request parameters are interpolated into log messages, error responses, or dynamic strings. For example, if an API key provided by a client is used to construct a log entry using a format string that relies on user input to determine formatting, an attacker can supply format verbs such as %s, %x, or %n to read stack memory or cause writes.

Consider an endpoint that logs received API keys for debugging:

let api_key = query_params.get("api_key").unwrap_or("");
info!("Received API key: {}", api_key); // Safe when using structured logging

This pattern is safe if the logging macro uses explicit formatting. However, a vulnerable pattern looks like this:

let user_input = query_params.get("format").unwrap_or("{}");
let message = format!(user_input, "test"); // UNSAFE: user_input controls the format string

If user_input contains format specifiers and an API key is also reflected in the response or logs, an attacker may read sensitive data or cause crashes. In the context of API keys, an attacker might submit a crafted format string in a header or query parameter to probe memory contents, potentially extracting parts of the API key or other secrets from the stack. Because Axum applications often integrate structured logging and validation layers, the risk is amplified when developers inadvertently pass unchecked user input into formatting routines that also handle authentication values.

Additionally, if an error response includes user-controlled data using unchecked format strings, it can lead to information disclosure. For instance, returning a message built with format!(user_provided_fmt, key=api_key) can expose the API key through format injection. The combination of dynamic formatting and sensitive authentication material like API keys creates a scenario where confidentiality and stability of the API can be compromised.

Api Keys-Specific Remediation in Axum — concrete code fixes

To remediate format string risks when handling API keys in Axum, always use explicit format strings and avoid passing user input directly to formatting macros. Prefer structured logging and strict input validation.

Safe logging of API keys

Use a logging framework that supports structured fields rather than string interpolation:

use tracing::info;

async fn handler(
    Query(params): Query<HashMap impl IntoResponse {
    if let Some(api_key) = params.get("api_key") {
        info!(api_key = &api_key[..], "API key received"); // Structured field, safe
        // Validate and use the key
    }
}

Avoiding format string injection

Never use user input as the format string. Instead, use fixed format strings and pass user data as arguments:

let user_fmt = query_params.get("fmt").unwrap_or("{}");
// Instead of: format!(user_fmt, api_key)
let safe_message = format!("{}", api_key); // Fixed format, user data as argument

Validation and rejection of suspicious input

Validate API keys and reject inputs that contain format specifiers when they are not expected:

fn is_valid_api_key(key: &str) -> bool {
    !key.contains('%') && key.len() == 32
}

async fn handler(
    Query(params): Query<HashMap<String, String>>
) -> Result<impl IntoResponse, (StatusCode, String)> {
    let api_key = params.get("api_key").ok_or_else(|| (StatusCode::BAD_REQUEST, "Missing key".into()))?;
    if !is_valid_api_key(api_key) {
        return Err((StatusCode::BAD_REQUEST, "Invalid key".into()));
    }
    // Proceed safely
    Ok((StatusCode::OK, "Valid key"))
}

Using proper escaping for dynamic content

If you must construct dynamic strings, ensure that format specifiers are escaped or use a templating engine with strict mode. For responses, prefer JSON serialization which does not involve format strings:

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

async fn respond_with_key(
    Query(params): Query<HashMap<String, String>>
) -> Json<serde_json::Value> {
    let api_key = params.get("api_key").unwrap_or("unknown");
    Json(json!({ "api_key": api_key })) // No format string involved
}

Frequently Asked Questions

How can I detect format string misuse in Axum API key handling during scanning?
middleBrick scans for patterns where user-controlled input influences formatting routines. It checks for direct use of variables in format macros and flags locations where API keys or headers are interpolated without explicit format strings, helping you locate risky concatenations.
Does middleBrick test for format string vulnerabilities specifically involving authentication values like API keys?
Yes, the security checks include input validation and output encoding tests that cover scenarios where authentication values such as API keys are reflected in responses or logs constructed via format strings.