HIGH pii leakageaxumapi keys

Pii Leakage in Axum with Api Keys

Pii Leakage in Axum with Api Keys — how this specific combination creates or exposes the vulnerability

Pii Leakage in an Axum service often occurs when API keys are handled in an unauthenticated or improperly constrained endpoint. Axum, a Rust web framework, does not enforce authentication by default; if route handlers accept an API key as a query parameter or header and then return resources that include personally identifiable information, the combination exposes PII to any unauthenticated caller.

Consider an endpoint that retrieves user profile details. If the handler validates the presence of an API key but does not enforce scope-based or ownership checks, an attacker can enumerate user IDs and harvest emails, phone numbers, or addresses. This is a BOLA/IDOR pattern enabled by weak authorization tied to API keys rather than a per-user identity. middleBrick’s unauthenticated scan flags this as Data Exposure with severity High, noting that API keys alone are insufficient to mediate access to PII.

Another scenario involves logging or error messages. If an Axum handler echoes the API key in logs or responses, and those logs or error payloads contain PII, the key and the sensitive data are co-located in outputs that may be exposed through monitoring or crash reports. This aligns with findings categorized under Unsafe Consumption, where structured output is not sanitized before being returned to the client. The scan also inspects OpenAPI specs for $ref definitions and runtime behavior; if the spec describes a 200 response containing fields like email or phone without tying them to authenticated user context, middleBrick correlates this with runtime observations to highlight PII leakage risks.

LLM/AI Security checks add another dimension: if an Axum endpoint is also an LLM inference endpoint, leaking API keys in prompts or model outputs can lead to prompt injection or cost exploitation. middleBrick’s active prompt injection probes and output scanning for PII, API keys, and executable code help identify whether API keys appear in LLM responses or system prompts, which would constitute a critical exposure.

Api Keys-Specific Remediation in Axum — concrete code fixes

Remediation centers on ensuring API keys are treated as authorization tokens, not identity, and that PII is only returned when the key maps to the correct subject. Use middleware to validate the key against a permissions store and bind it to a user identifier before allowing access to sensitive fields.

Example 1: Scoped API key validation that restricts data to the owning user.

use axum::{routing::get, Router, extract::State, http::HeaderMap};
use std::sync::Arc;
use serde::Serialize;

#[derive(Clone)]
struct AppState {
    key_store: Arc<KeyStore>,
}

#[derive(Serialize)]
struct UserProfile {
    user_id: u64,
    email: String,
    // Do not include PII unless key scope matches
}

async fn get_profile(
    State(state): State<Arc<AppState>>,
    headers: HeaderMap,
) -> Result<String, (axum::http::StatusCode, String)> {
    let api_key = headers.get("X-API-Key")
        .ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing API key"))?
        .to_str()
        .map_err(|_| (axum::http::StatusCode::BAD_REQUEST, "Invalid header"))?;

    let key_record = state.key_store.lookup(api_key)
        .await
        .ok_or((axum::http::StatusCode::FORBIDDEN, "Invalid API key"))?;

    // Enforce scope: only allow access if the key is scoped to this user
    if key_record.user_id != key_record.allowed_user_id {
        return Err((axum::http::StatusCode::FORBIDDEN, "Insufficient scope").into());
    }

    let profile = UserProfile {
        user_id: key_record.user_id,
        email: key_record.email.clone(),
    };
    let body = serde_json::to_string(&profile).unwrap();
    Ok(body)
}

#[tokio::main]
async fn main() {
    let state = Arc::new(AppState {
        key_store: Arc::new(KeyStore::new()),
    });
    let app = Router::new()
        .route("/profile", get(get_profile))
        .with_state(state);
    axum::Server::bind("0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

Example 2: Centralized middleware that validates API keys and attaches user claims, preventing PII leakage by ensuring downstream handlers only receive authorized data.

use axum::{routing::get, Router, Extension, http::HeaderMap};
use std::sync::Arc;
use tower_http::ServiceBuilderExt;

struct KeyValidator;
impl KeyValidator {
    async fn validate(headers: &HeaderMap) -> Result<Claims, (axum::http::StatusCode, String)> {
        let key = headers.get("X-API-Key")
            .and_then(|v| v.to_str().ok())
            .ok_or((axum::http::StatusCode::UNAUTHORIZED, "Invalid key header"))?;
        // Replace with actual lookup; ensure claims do not include raw PII unless necessary
        if key == "valid_scoped_key" {
            Ok(Claims { user_id: 1, scope: "profile:read" })
        } else {
            Err((axum::http::StatusCode::FORBIDDEN, "Invalid scope").into())
        }
    }
}

async fn get_user(
    Extension(claims): Extension<Claims>,
) -> String {
    // Return only non-PII or PII explicitly allowed by scope
    format!({{"user_id": {}}} , claims.user_id)
}

// In router setup:
// let app = Router::new()
//     .route("/user", get(get_user.layer(Extension(key_validator_middleware))))
//     .layer(Extension(key_validator));

These examples demonstrate how to bind API key validation to user identity and scope, ensuring PII is only surfaced when authorization matches. middleBrick’s CLI can be used to verify these changes: scan from terminal with middlebrick scan to confirm that endpoints no longer leak PII when API keys are improperly scoped.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

Why does an API key not prevent PII leakage on its own?
An API key proves request authorization but does not encode identity or scope. Without mapping the key to a user and enforcing ownership checks, any caller with the key can access PII, creating BOLA/IDOR risks.
How does middleBrick detect PII leakage in Axum APIs?
middleBrick runs unauthenticated scans combining OpenAPI/Swagger spec analysis with runtime probes. It checks for endpoints that return PII fields while accepting API keys without user-bound validation, and correlates spec definitions with observed outputs to highlight Data Exposure findings.