HIGH api key exposureaxummutual tls

Api Key Exposure in Axum with Mutual Tls

Api Key Exposure in Axum with Mutual Tls

Api key exposure in an Axum service using mutual TLS (mTLS) can occur when an API key is accepted as a credential alongside mTLS but is handled inconsistently across the application stack. Axum does not enforce mTLS itself; the TLS termination is handled by the hosting environment (load balancer, ingress controller, or reverse proxy). If the environment forwards the request to Axum over HTTP rather than HTTPS, or if the application layer reads the API key from an untrusted source, the intended binding between client certificate identity and the key can be bypassed.

Consider a scenario where an Axum handler retrieves an API key from a custom header (e.g., x-api-key) and uses it for authorization, while also verifying the client certificate at the edge. An incomplete integration between the edge verification and the application logic may lead to the key being accepted even when the client certificate is missing or invalid. This inconsistency creates a path where an attacker who discovers or guesses a valid API key can access protected endpoints without presenting the expected client certificate, undermining the purpose of mTLS.

Another vector involves logging or error messages that inadvertently expose the API key. If Axum logs incoming headers for debugging and the x-api-key header is included, the key may be persisted in log stores accessible to unauthorized parties. Similarly, misconfigured tracing or monitoring integrations that capture header values can amplify exposure. Because mTLS ensures channel integrity between client and edge, developers might mistakenly assume that application-level handling is inherently safe, leading to insufficient validation of the key’s presence and correctness within Axum handlers.

Additionally, if the API key is embedded in request bodies or query parameters while mTLS is used for channel authentication, an inconsistent security boundary may emerge. For example, a frontend service might terminate mTLS at a gateway and forward requests to Axum over an internal network without stripping or re-validating the key. In such setups, if internal network trust is assumed, the key may be passed without further verification, increasing the risk of accidental exposure through internal service logs or misrouted requests.

To detect this category of issue, scans examine whether the API key is accepted as a primary or secondary credential, whether it is transmitted in clear text in headers or logs, and whether its validation is consistently enforced alongside mTLS verification. The presence of the key in query strings or error responses is treated as a high-severity finding due to the elevated risk of exfiltration through logs or browser history.

Mutual Tls-Specific Remediation in Axum

Remediation focuses on ensuring that the API key is treated as a secondary credential that is validated only after mTLS verification has been confirmed at the edge. The key should never be the sole authentication mechanism when mTLS is in use, and its presence must be checked in a way that is tightly coupled with the certificate identity. Below are concrete Axum examples that demonstrate secure handling patterns.

First, ensure that the edge layer enforces mTLS and strips or masks the client certificate information before forwarding to Axum. The application should then validate the key only if the certificate-based identity is present and authorized. Here is an Axum handler that expects the client identity to be injected by the proxy (for example, via a header like x-client-identity) and validates the API key from a secure source:

use axum::{routing::get, Router, extract::State};
use std::sync::Arc;

struct AppState {
    valid_keys: std::collections::HashSet,
    // identity injected by the proxy after mTLS verification
    client_identity: Option,
}

async fn handler(
    State(state): State>,
    headers: axum::http::HeaderMap,
) -> Result {
    // 1) Ensure mTLS-derived identity is present (injected by edge)
    let identity = state.client_identity
        .as_ref()
        .ok_or_else(|| (axum::http::StatusCode::FORBIDDEN, "mTLS identity missing".to_string()))?;

    // 2) Extract API key from a non-logged header if needed; prefer runtime injection over request header
    let api_key = headers.get("x-api-key")
        .and_then(|v| v.to_str().ok())
        .ok_or_else(|| (axum::http::StatusCode::BAD_REQUEST, "missing api key".to_string()))?;

    // 3) Validate key against a secure store (e.g., database or vault); avoid logging the key
    if state.valid_keys.contains(api_key) {
        Ok(format!("Access granted for {identity}"))
    } else {
        Err((axum::http::StatusCode::UNAUTHORIZED, "invalid api key".to_string()))
    }
}

#[tokio::main]
async fn main() {
    let state = Arc::new(AppState {
        valid_keys: ["s3cr3t-k3y".to_string()].into_iter().collect(),
        client_identity: None, // injected by proxy in real deployment
    });

    let app = Router::new()
        .route("/secure", get(handler))
        .with_state(state);

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

In production, the client_identity should be injected by the proxy (for example, an ingress controller that validates the client certificate and sets a trusted header). The Axum application must not trust the header directly; instead, the proxy must ensure that only requests with valid mTLS are forwarded. The API key should be retrieved from a secure configuration or vault at startup and never echoed in responses or logs. Avoid including the key in URLs or query parameters to prevent leakage in server logs and browser history.

For automated verification, middleBrick scans can be added to your CI/CD pipeline using the GitHub Action to ensure that API key handling remains consistent with mTLS expectations. The CLI tool allows you to test endpoints from the terminal with middlebrick scan <url> to confirm that keys are not exposed in logs or error messages.

FAQ

  • Can mTLS alone replace API keys in Axum?

    mTLS provides strong channel-level authentication and can be sufficient on its own. Using an API key in addition is only necessary if you require an additional revocation mechanism or need to delegate authorization to services that cannot present client certificates. If you do use both, ensure the key is validated after mTLS identity is verified and is never the sole gatekeeper.

  • How does middleBrick detect API key exposure with mTLS setups?

    middleBrick performs unauthenticated scans that include checks for sensitive data exposure and inconsistencies in authentication mechanisms. It does not rely on internal architecture details but analyzes observable behavior, such as whether API keys appear in logs, error messages, or query strings, and whether key validation is misaligned with mTLS verification.

Frequently Asked Questions

Can mTLS alone replace API keys in Axum?
mTLS provides strong channel-level authentication and can be sufficient on its own. Using an API key in addition is only necessary if you require an additional revocation mechanism or need to delegate authorization to services that cannot present client certificates. If you do use both, ensure the key is validated after mTLS identity is verified and is never the sole gatekeeper.
How does middleBrick detect API key exposure with mTLS setups?
middleBrick performs unauthenticated scans that include checks for sensitive data exposure and inconsistencies in authentication mechanisms. It does not rely on internal architecture details but analyzes observable behavior, such as whether API keys appear in logs, error messages, or query strings, and whether key validation is misaligned with mTLS verification.