HIGH bola idoraxummutual tls

Bola Idor in Axum with Mutual Tls

Bola Idor in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability

Broken Object Level Authorization (BOLA) in an Axum API protected with Mutual TLS (mTLS) can occur when the mTLS handshake is treated as sufficient authorization. mTLS ensures that both client and server present valid certificates, but it does not inherently convey application-level permissions. If route handlers in Axum use the presence of a valid client certificate as a proxy for identity-based access control, they may fail to verify that the authenticated principal is allowed to access the specific resource identifier (e.g., /users/{id}).

An attacker who obtains a valid client certificate (e.g., via theft, provisioning abuse, or a compromised intermediate CA) can still iterate over IDs (IDs 1..N) and access other users’ data because the server never enforces ownership or role checks. In Axum, this typically manifests when handlers extract the certificate subject or serial but then skip object-level authorization checks, assuming the TLS layer has already ‘proven’ the right to access. For example, a handler that only checks that a certificate is valid and maps the certificate to a user ID, then returns user data for that ID without confirming that the requested {id} matches the authenticated principal’s ID, exposes BOLA.

Moreover, mTLS complicates tracing because some teams mistakenly treat it as end-to-end authorization and reduce logging or skip additional checks for performance reasons. The Axum runtime does not automatically enforce object-level boundaries; you must implement them in your extractors or guards. Even with mTLS, an unauthenticated attacker without a valid cert is blocked, but an authenticated attacker with a valid cert can still exploit weak authorization logic.

Mutual Tls-Specific Remediation in Axum — concrete code fixes

To prevent BOLA in Axum with mTLS, couple certificate validation with explicit application-level authorization checks. Do not rely on mTLS alone to enforce object ownership. Below are concrete, realistic code examples for Axum that show how to validate a client certificate and then enforce per-request authorization.

First, configure mTLS in Axum using tower-http’s rustls integration to require client certificates:

use axum::Router;
use std::net::SocketAddr;
use tower_http::rustls::RustlsConfig;

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/users/:id", axum::routing::get(get_user))
        .with_state(AppState::new())
        .tls_config(RustlsConfig::from_pem_file(
            "path/to/ca-cert.pem",
            "path/to/server-cert.pem",
            "path/to/server-key.pem",
        ).expect("valid TLS config"));

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

Next, extract the client certificate in an extractor and enforce ownership in the handler. A safe pattern is to map the certificate to an identity and then verify that the requested resource belongs to that identity:

use axum::{routing::get, Router, extract::State, http::Request, body::Body};
use axum::extract::RequestExt;
use rustls_pemfile::{certs, pkcs8_private_keys};
use std::sync::Arc;
use std::fs::File;
use std::io::BufReader;

struct AppState {
    // Your data store
}

async fn get_user(
    State(state): State>,
    // Custom extractor that validates mTLS and returns the user_id from the cert
    user_identity: UserIdentity,
    axum::extract::Path(id): axum::extract::Path,
) -> Result {
    // BOLA guard: ensure the requesting user can only access their own resource
    if user_identity.user_id != id {
        return Err((axum::http::StatusCode::FORBIDDEN, "Not allowed".to_string()));
    }
    // Fetch user data for id (which is guaranteed to match user_identity.user_id)
    Ok(format!("User data for {}", id))
}

// A simple extractor that validates the client cert and maps it to a user_id
pub struct UserIdentity {
    pub user_id: u64,
}

impl axum::extract::FromRequest for UserIdentity
where
    S: Send + Sync,
{
    type Rejection = (axum::http::StatusCode, String);

    async fn from_request(req: Request) -> Result {
        // Obtain the peer certificate from the TLS connection (pseudo-code)
        let peer_certs = req.extensions()
            .get::>()
            .ok_or((axum::http::StatusCode::UNAUTHORIZED, "Missing client certificate".to_string()))?;

        // In practice, parse the certificate and extract a user identifier (e.g., from SAN or subject)
        // This is a simplified example: assume a mapping from cert fingerprint to user_id
        let user_id = map_cert_to_user_id(&peer_certs[0])?;
        Ok(UserIdentity { user_id })
    }
}

fn map_cert_to_user_id(cert: &rustls::Certificate) -> Result {
    // Example: compute SHA-256 fingerprint and map to user_id
    use sha2::{Sha256, Digest};
    let mut hasher = Sha256::new();
    hasher.update(&cert.0);
    let fingerprint = hasher.finalize();
    // Dummy mapping; replace with your directory lookup
    match fingerprint[..4].try_into() {
        Ok(bytes) => Ok(u64::from_be_bytes(bytes)),
        Err(_) => Err((axum::http::StatusCode::FORBIDDEN, "Invalid certificate".to_string())),
    }
}

Key points:

  • Always compare the authenticated principal (derived from the client certificate) with the requested resource ID in the handler.
  • Do not skip authorization because mTLS was used; treat the certificate as identity proof, not as authorization.
  • Use fine-grained checks (e.g., per-route guards) and avoid broad assumptions that a valid cert equals permission to all resources.

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

Does mTLS alone prevent BOLA in Axum?
No. mTLS authenticates the client but does not enforce object-level permissions. You must add explicit authorization checks in Axum handlers to prevent BOLA.
How can I test for BOLA with mTLS in my Axum API?
Use a valid client certificate to request other users’ resources (e.g., /users/1, /users/2). If the server returns data without verifying ownership, BOLA exists. middleBrick can scan such endpoints to detect missing authorization controls.