Integrity Failures in Axum with Mutual Tls
Integrity Failures in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability
In Axum, enabling mutual TLS (mTLS) means both the server and the client present certificates during the TLS handshake. When mTLS is configured but the server does not validate client certificates or does not enforce the intended trust boundaries, integrity failures can occur. An attacker could present a certificate signed by an untrusted CA, or a revoked certificate, and the server may still accept it as authenticated. This breaks integrity because the server treats an unverified client as a trusted peer, allowing tampered requests to be processed as if they originated from an authorized client.
These integrity failures are specific to the Axum + mTLS combination because Axum relies on the underlying hyper‑tls/rustls integration and the application’s explicit verification logic. If the developer configures TLS acceptor options but omits hostname verification or certificate chain validation, the server may accept connections that should have been rejected. Common missteps include using a permissive certificate verification callback, failing to check revocation via CRL/OCSP, or not constraining the allowed distinguished names (DNs) or extended key usage (EKU). Such gaps allow manipulated or spoofed client identities to influence business logic, leading to privilege escalation or unauthorized data access.
Real-world attack patterns that exploit these integrity issues include presenting a certificate intended for a less privileged service to access admin endpoints, or exploiting weak validation to bypass role-based checks that the application layer assumes are enforced by mTLS. For example, an API endpoint that relies on the client DN to assign permissions may be tricked into granting elevated permissions if the server does not validate the certificate chain and EKU. These scenarios map to OWASP API Security Top 10 controls around authentication and authorization failures and can violate compliance frameworks such as PCI-DSS and SOC2 that require strong identity proofing.
middleBrick detects these integrity risks by analyzing your OpenAPI specification and runtime behavior, checking whether mTLS configurations are enforced consistently and whether client identity is properly validated. The scanner highlights missing certificate validation steps, permissive verification settings, and gaps that could allow spoofed clients. By correlating spec definitions with observed behavior, it helps you confirm that your Axum service enforces integrity for every mTLS-secured route.
Mutual Tls-Specific Remediation in Axum — concrete code fixes
To remediate integrity failures in Axum with mTLS, enforce strict certificate validation on the server side and ensure client certificates are verified against a trusted CA store. Below are concrete, working examples using rustls and Axum that demonstrate proper mTLS setup with hostname and certificate validation.
use axum::Server;
use std::net::SocketAddr;
use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};
use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer, UnixTime};
use tokio_rustls::TlsAcceptor;
use std::sync::Arc;
use std::fs::File;
use std::io::BufReader;
// Load server certificate and private key
let certs = load_certs("server-cert.pem")?;
let key = load_private_key("server-key.pem")?;
// Load trusted CA certificates for client verification
let client_ca_certs = load_client_ca_certs("ca-cert.pem")?;
let mut server_config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth() // we will set client auth later
.with_single_cert(certs, key)?;
// Configure client certificate verification
server_config.client_auth_root_certificates(client_ca_certs);
server_config.verify_client_cert_root_subjects(|subjects| {
// Optionally restrict to specific subject DNs or EKUs
subjects.iter().any(|s| s.contains("CN=trusted-client"))
});
let tls_acceptor = TlsAcceptor::from(Arc::new(server_config));
let app = axum::Router::new()
.route("/", axum::routing::get(|| async { "Hello over mTLS" }));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
Server::bind(&addr)
.https(tls_acceptor)
.serve(app.into_make_service())
.await?;
// Helper functions (implement securely):
fn load_certs(path: &str) -> Result<Vec<CertificateDer<'static>>, Box<dyn std::error::Error>> {
let file = &mut BufReader::new(File::open(path)?);
Ok(certificates_from_pem(file)?.into_iter().collect())
}
fn load_private_key(path: &str) -> Result<PrivateKeyDer<'static>, Box<dyn std::error::Error>> {
let file = &mut BufReader::new(File::open(path)?);
let mut keys = private_key_from_pem(file)?;
keys.pop().ok_or_else(|| "No private key found".into())
}
fn load_client_ca_certs(path: &str) -> Result<rustls::RootCertStore, Box<dyn std::error::Error>> {
let file = &mut BufReader::new(File::open(path)?);
let mut roots = rustls::RootCertStore::empty();
for cert in rustls_pemfile::certs(file)? {
roots.add(&CertificateDer::from(cert?))?;
}
Ok(roots)
}
fn certificates_from_pem(
reader: &mut dyn std::io::BufRead,
) -> Result<Vec<CertificateDer<'static>>, rustls::Error> {
let mut certs = Vec::new();
for cert in rustls_pemfile::certs(reader)? {
certs.push(CertificateDer::from(cert?));
}
Ok(certs)
}
fn private_key_from_pem(
reader: &mut dyn std::io::BufRead,
) -> Result<Vec<PrivateKeyDer<'static>>, rustls::Error> {
let mut keys = Vec::new();
for key in rustls_pemfile::rsa_private_keys(reader)? {
keys.push(PrivateKeyDer::from(key?));
}
for key in rustls_pemfile::ec_private_keys(reader)? {
keys.push(PrivateKeyDer::from(key?));
}
Ok(keys)
}
This example ensures that the server requests and validates client certificates, restricts accepted root subjects, and uses safe defaults. To further reduce integrity risks, add OCSP stapling checks or CRL validation in production, and avoid permissive subject filters. middleBrick’s Pro plan supports continuous monitoring, so you can schedule regular scans to verify that these mTLS controls remain intact after code changes.
Additionally, if you use the CLI to integrate scans into scripts, you can run middlebrick scan <url> to detect missing mTLS enforcement or client validation issues in your deployed endpoints. For CI/CD, the GitHub Action can fail the build if the risk score drops below your configured threshold, preventing insecure mTLS configurations from reaching production.