HIGH jwt misconfigurationactixmutual tls

Jwt Misconfiguration in Actix with Mutual Tls

Jwt Misconfiguration in Actix with Mutual Tls — how this specific combination creates or exposes the vulnerability

JWT misconfiguration in Actix when combined with Mutual TLS (mTLS) can create a situation where authentication is partially enforced but authorization and token validation are incomplete, leading to security gaps. mTLS ensures that both the client and server present valid certificates, providing strong transport-layer identity. However, mTLS does not inherently validate the contents or signature of a JWT. If an API endpoint relies solely on mTLS for authentication and fails to enforce strict JWT checks, an attacker who compromises a client certificate can submit unsigned or malformed tokens that the server may incorrectly accept.

In Actix, a common misconfiguration is enabling mTLS via rustls but skipping mandatory JWT validation middleware or accepting tokens with weak algorithms (e.g., none). For example, if the server trusts the client certificate but does not verify the JWT signature, issuer, audience, or expiration, an attacker could capture a valid mTLS session and inject a crafted JWT with elevated claims. This bypasses the intended identity binding provided by mTLS and violates the principle that transport-layer authentication should be complemented by application-layer token validation.

Another specific risk arises when Actix services propagate JWTs across internal services after mTLS-established connections. If internal service-to-service calls reuse the same JWT without revalidation or if the JWT contains excessive permissions (overly broad scopes), the combination of mTLS and permissive JWT handling can lead to privilege escalation. For instance, a gateway terminating mTLS might forward requests with the original JWT to downstream microservices that do not independently verify the token, effectively bypassing intended authorization boundaries. The OWASP API Security Top 10 category Broken Object Level Authorization (BOLA) often intersects with this pattern when JWT claims are not rigorously enforced at each service boundary.

Real-world attack patterns include token replay over an mTLS channel and injection of tokens obtained via other vectors into a trusted mTLS session. Since mTLS provides server and client authentication at the TLS layer, developers may mistakenly assume that JWT validation is redundant. This assumption is dangerous: mTLS protects against impersonation at the network layer but does not prevent tampered or stolen JWTs from being accepted if the application does not validate signatures, algorithms, and claims. Therefore, JWT misconfiguration in Actix with mTLS creates a scenario where strong transport security coexists with weak or missing token validation, increasing the risk of unauthorized access and data exposure.

Mutual Tls-Specific Remediation in Actix — concrete code fixes

To remediate JWT misconfiguration in Actix when using Mutual TLS, you must enforce strict JWT validation in addition to mTLS. Below are concrete code examples showing how to configure Actix with rustls for mTLS and apply JWT validation using the jsonwebtoken crate. These examples assume you have certificate authorities, server certificates, and client certificates in PEM format.

1. Configure rustls server with mTLS in Actix

Set up an Actix server that requires client certificates for mTLS. This ensures only clients with a trusted certificate can establish a TLS connection.

use actix_web::{web, App, HttpServer}; 
use rustls::{Certificate, PrivateKey, ServerConfig}; 
use rustls_pemfile::{certs, pkcs8_private_keys}; 
use std::fs::File; 
use std::io::BufReader; 

async fn run_mtls_server() -> std::io::Result<()> { 
    // Load server certificate and private key 
    let mut cert_file = BufReader::new(File::open("server-cert.pem").unwrap()); 
    let cert_chain: Vec<Certificate> = certs(&mut cert_file).unwrap().into_iter().map(Certificate).collect(); 
    let mut key_file = BufReader::new(File::open("server-key.pem").unwrap()); 
    let mut keys: Vec<PrivateKey> = pkcs8_private_keys(&mut key_file).unwrap(); 

    // Configure ClientAuthRequired to enforce mTLS 
    let mut config = ServerConfig::builder() 
        .with_safe_defaults() 
        .with_no_client_auth() // Start without client auth 
        .with_single_cert(cert_chain, keys.remove(0)) 
        .unwrap(); 

    // Require and verify client certificates 
    config.client_auth_root_subjects = Some(vec!["/C=US/O=Example CA".parse().unwrap()]); 
    config.client_auth_mandatory = true; 

    HttpServer::new(|| { 
        App::new() 
            .route("/secure", web::get().to(secure_handler)) 
    }) 
    .bind_rustls("127.0.0.1:8443", config)? 
    .run() 
    .await 
} 

async fn secure_handler() -> &'static str { 
    "OK" 
}

2. Add JWT validation middleware after mTLS connection

Even with mTLS, validate JWTs on each request. Use jsonwebtoken to decode and verify the token’s algorithm, signature, issuer, audience, and expiration.

use actix_web::{dev::ServiceRequest, Error, HttpMessage}; 
use actix_web_httpauth::extractors::bearer::BearerAuth; 
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; 
use serde::{Deserialize, Serialize}; 

#[derive(Debug, Serialize, Deserialize)] 
struct Claims { 
    sub: String, 
    scope: String, 
    exp: usize, 
    iss: String, 
    aud: String, 
} 

async fn validate_jwt(req: ServiceRequest) -> Result<ServiceRequest, Error> { 
    let auth_header = req.headers().get("Authorization"); 
    let token = if let Some(header) = auth_header { 
        header.to_str().unwrap_or("").trim_start_matches("Bearer ").to_string() 
    } else { 
        return Err(actix_web::error::ErrorUnauthorized("Missing Authorization header")); 
    }; 

    let validation = Validation::new(Algorithm::RS256); 
    let token_data = decode::( 
        &token, 
        &DecodingKey::from_rsa_pem(include_bytes!("public-key.pem")).map_err(|_| actix_web::error::ErrorUnauthorized("Invalid key"))?, 
        &validation, 
    ).map_err(|_| actix_web::error::ErrorUnauthorized("Invalid token"))?; 

    // Enforce audience and issuer checks 
    if token_data.claims.iss != "https://auth.example.com" { 
        return Err(actix_web::error::ErrorUnauthorized("Invalid issuer")); 
    } 
    if token_data.claims.aud != "https://api.example.com" { 
        return Err(actix_web::error::ErrorUnauthorized("Invalid audience")); 
    } 

    // Attach claims to request extensions for downstream handlers 
    req.extensions_mut().insert(token_data.claims); 
    Ok(req) 
}

3. Combine mTLS and JWT checks in a guard

Use a custom guard or extractor to ensure both mTLS client identity and a valid JWT are present. This prevents scenarios where a valid client certificate is used with an invalid or missing token.

use actix_web::{web, Error, HttpRequest}; 

async fn jwt_mtls_guard(req: HttpRequest) -> Result<(), Error> { 
    // mTLS client identity is available via request extensions (rustls sets this) 
    let client_cert_present = req.extensions().get::().is_some(); 
    if !client_cert_present { 
        return Err(actix_web::error::ErrorForbidden("Client certificate required")); 
    } 

    // JWT validation already performed in middleware; ensure claims exist 
    let claims = req.extensions().get::().ok_or_else(|| actix_web::error::ErrorUnauthorized("Missing JWT claims"))?; 
    if claims.scope != "admin" { 
        return Err(actix_web::error::ErrorForbidden("Insufficient scope")); 
    } 
    Ok(()) 
}

By requiring both mTLS and strict JWT validation, you ensure that transport-layer identity and application-layer authorization are independently enforced. This approach mitigates the risk of JWT misconfiguration while preserving the security benefits of Mutual TLS.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Can mTLS alone replace JWT validation in Actix?
No. mTLS authenticates the client at the transport layer but does not validate JWT claims, signatures, or scopes. Always enforce JWT validation in addition to mTLS to prevent token replay and privilege escalation.
What OWASP API Top 10 category relates to JWT misconfiguration with mTLS?
Broken Object Level Authorization (BOLA). Even with mTLS, missing or weak JWT checks can allow attackers to escalate privileges or access unauthorized resources by manipulating token claims.