HIGH cors wildcardaxummutual tls

Cors Wildcard in Axum with Mutual Tls

Cors Wildcard in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability

A CORS wildcard (Access-Control-Allow-Origin: *) combined with Mutual TLS (mTLS) in an Axum service can unintentionally broaden the attack surface in ways that bypass origin-based protections. In Axum, CORS is typically configured via the axum::cors::CorsLayer. When a wildcard is used while mTLS is also enforced, the server signals that any origin can access resources, even though each request must present a valid client certificate. The critical issue is not that mTLS is weak, but that the CORS policy is too permissive relative to the trust boundary established by mTLS.

With mTLS, the server authenticates the client based on a certificate chain. This is strong identity assurance at the transport layer. However, CORS operates at the HTTP application layer and governs which origins JavaScript running in browsers may access the response. A wildcard Access-Control-Allow-Origin ignores the origin entirely, which means even if an attacker cannot present a valid client certificate to reach the endpoint directly, a malicious webpage served from any origin could still process responses if the browser forwards credentials (e.g., cookies or client-side certificates) and the CORS headers permit it.

In Axum, this often manifests when developers enable mTLS for strict client authentication but also apply a global CORS layer with .allow_origin(Any). Consider an endpoint that returns sensitive data and uses mTLS for authorization. If CORS allows any origin, a compromised frontend on any domain can make authenticated requests via JavaScript, leveraging the browser’s automatic inclusion of client-side credentials where mTLS is configured to send client certificates. This mismatched security perimeter—one layer enforces strict identity, while the other ignores origin—creates a confusion-of-trust scenario that middleBrick flags under BFLA/Privilege Escalation and Property Authorization checks.

Real-world examples include single-page applications hosted on a different domain than the API. An attacker could host a malicious page that calls the mTLS-protected API. If the API responds with *, the browser will allow the malicious page to read the response if credentials are included, potentially leaking data or performing actions on behalf of the authenticated client. This pattern is explicitly tested by middleBrick’s 12 security checks, including its LLM/AI Security probes for system prompt leakage and unauthorized data exfiltration paths.

To detect such misconfigurations, middleBrick scans unauthenticated attack surfaces and maps findings to frameworks like OWASP API Top 10 and SOC2. Its per-category breakdowns show how a CORS wildcard with mTLS in Axum affects Authorization and CORS-specific checks. Developers can use the CLI tool (middlebrick scan <url>) or the Web Dashboard to review these findings and understand remediation steps without needing to configure agents or credentials.

Mutual Tls-Specific Remediation in Axum — concrete code fixes

Remediation focuses on aligning CORS policy with the trust boundary enforced by mTLS. Instead of a wildcard, explicitly allow only the origins that are expected to interact with the API. In Axum, this is done by configuring CorsLayer with specific origins and ensuring that mTLS remains required for all relevant routes.

Below is a concrete, working Axum example that demonstrates secure configuration. It sets up mTLS using rustls and applies a strict CORS policy allowing only specific origins. The server requires client certificates and only responds to requests from those origins, preventing unauthorized cross-origin access even when credentials are present.

use axum::cors::{Cors, CorsLayer};
use axum::routing::get;
use axum::Router;
use std::net::SocketAddr;
use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};
use tokio_rustls::TlsAcceptor;
use std::sync::Arc;

async fn handler() -> &'static str {
    "Secure response"
}

#[tokio::main]
async fn main() {
    // Load server certificate and key
    let certs = vec![Certificate(include_bytes("server.crt").to_vec())];
    let key = PrivateKey(include_bytes("server.key").to_vec());

    // Configure server-side TLS with client authentication required
    let mut server_config = ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth() // We will override to require client certs
        .with_single_cert(certs, key)
        .expect("invalid server certificate or key");

    // Require client certificate verification
    server_config.client_auth_verifier = Arc::new(
        tokio_rustls::rustls::client::ClientCertVerified::assert_client_certified()
    );
    let tls_acceptor = TlsAcceptor::from(Arc::new(server_config));

    // Define allowed origins explicitly — never use wildcard with mTLS
    let cors = Cors::builder()
        .allow_origin(vec!["https://app.example.com".parse().unwrap(), "https://admin.example.com".parse().unwrap()])
        .allow_methods(vec!["GET", "OPTIONS"])
        .allow_headers(vec!["authorization", "content-type"])
        .allow_credentials(true)
        .build();

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

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
    let tls_listener = tokio_rustls::TlsListener::from_listener(listener, tls_acceptor);

    axum::serve(tls_listener, app).await.unwrap();
}

In this example, the CORS layer specifies exact origins rather than a wildcard. The mTLS configuration requires clients to present a valid certificate that the server can verify. This ensures that only known origins can access protected responses and that each request is authenticated at the transport layer. middleBrick’s scans would validate that the CORS headers do not use * and that the endpoint properly enforces mTLS, reducing the risk of privilege escalation or unauthorized data exposure.

For teams using the Pro plan, continuous monitoring can be enabled to alert on CORS or TLS configuration drift. The GitHub Action can fail builds if a scan detects a wildcard origin in endpoints that require authentication, providing CI/CD pipeline gates. The MCP Server allows developers to run scans directly from their IDE when modifying Axum routes, supporting rapid feedback without leaving the development environment.

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

Can a CORS wildcard be safe if mTLS is enforced?
No. A CORS wildcard ignores the origin, which allows any webpage to make authenticated requests in the browser, potentially bypassing intended access controls even when mTLS verifies client identity.
How does middleBrick detect CORS wildcard issues with mTLS in Axum?
middleBrick runs checks for CORS misconfiguration and authorization scope. It identifies responses with Access-Control-Allow-Origin: * on endpoints that require authentication, mapping findings to relevant compliance frameworks and providing remediation guidance.