HIGH dns rebindingaxummutual tls

Dns Rebinding in Axum with Mutual Tls

Dns Rebinding in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability

DNS rebinding is a client-side attack where a malicious webpage changes the IP address of a domain after initial resolution to make the victim’s browser connect to an internal or unintended host. In Axum, enabling mutual TLS (mTLS) primarily ensures that both client and server present valid certificates, but it does not protect against DNS rebinding because the TLS handshake completes before HTTP routing occurs. If your Axum service uses mTLS to authorize clients based on certificate fields (e.g., common name or SAN), an attacker can first resolve a domain to a legitimate, trusted IP (e.g., a public load balancer with valid certs), complete the TLS handshake successfully, then rebind the DNS name to an internal service (such as 127.0.0.1 or an internal Kubernetes pod). Because mTLS is already satisfied, Axum treats the request as authenticated and may route it based on path or authorization logic that assumes the client originated from the expected external network boundary.

Specifically in Axum, if you use certificate information in your authorization logic (for example, extracting a principal from peer certs via tower::ServiceBuilder extensions or custom middleware), DNS rebinding can trick the service into trusting an internal endpoint. Even with mTLS, the HTTP request path may invoke handlers that expose admin or diagnostic routes, internal APIs, or sensitive data, because the router does not re-validate the resolved IP against the certificate’s identity. A common misconfiguration is to rely solely on client certificate validity without enforcing strict hostname or IP constraints at the application layer. This means an attacker can pivot from an externally trusted domain to internal infrastructure, bypassing network segregation that mTLS alone does not enforce. For this reason, mTLS in Axum should be combined with explicit hostname verification and request validation to mitigate DNS rebinding.

To detect this using middleBrick, you can run a scan against your Axum endpoint. middleBrick’s unauthenticated black-box checks include input validation, authorization, and SSRF-related tests that can surface indicators of rebinding risk when combined with mTLS endpoints. Its LLM/AI security checks are not relevant here; the focus is on how routing and certificate-based auth interact with DNS behavior. The scanner does not fix the issue but provides prioritized findings with remediation guidance, helping you understand whether your route handling and certificate checks are sufficient to prevent internal access via rebinding.

Mutual Tls-Specific Remediation in Axum — concrete code fixes

To secure Axum services against DNS rebinding when using mutual TLS, you must couple mTLS with explicit hostname verification and avoid relying on certificate metadata alone for routing decisions. Below are concrete code examples that demonstrate a hardened Axum setup.

1. Configure TLS with client certificate verification and hostname checks using rustls. This example loads server and client CA certificates, requires client certs, and verifies that the peer hostname matches the certificate.

use axum::Server;
use rustls::{Certificate, PrivateKey, ServerConfig};
use rustls_pemfile::{certs, pkcs8_private_keys};
use std::fs::File;
use std::io::BufReader;
use std::net::SocketAddr;
use std::sync::Arc;

async fn make_config() -> Arc<ServerConfig> {
    let mut cert_file = BufReader::new(File::open("ca.crt").unwrap());
    let mut key_file = BufReader::new(File::open("server.key").unwrap());
    let cert_chain: Vec<Certificate> = certs(&mut cert_file).unwrap().into_iter().map(Certificate).collect();
    let mut keys: Vec<PrivateKey> = pkcs8_private_keys(&mut key_file).unwrap().into_iter().map(PrivateKey).collect();

    let mut server_config = ServerConfig::builder()
        .with_safe_defaults()
        .with_client_cert_verifier(Arc::new(MyClientVerifier::new())) // custom verifier with hostname checks
        .with_single_cert(cert_chain, keys.remove(0))
        .unwrap();
    server_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
    Arc::new(server_config)
}

struct MyClientVerifier {
    ca: CertificateAuthority,
}
impl MyClientVerifier {
    fn new() -> Self {
        // Load CA that signed client certs and implement validation + hostname checks
        Self { ca: CertificateAuthority::new() }
    }
}
// Implement rustls::server::ClientCertVerifier for MyClientVerifier
// Ensure verify_client_cert includes checking the client identity (e.g., SAN/CN) against allowed origins

2. In your Axum routing layer, avoid trusting peer-derived metadata for authorization. Instead, explicitly validate the request target and enforce that internal hostnames are never reachable. Use a middleware that checks an allowlist of permitted hostnames when mTLS is used.

use axum::extract::Request;
use axum::middleware::Next;
use axum::response::Response;

async fn hostname_allowlist_middleware(
    request: Request,
    next: Next<Response>,
) -> Response {
    // Example: reject requests where the Host header or TLS server name does not match expected patterns
    let host = request.headers().get("host").and_then(|h| h.to_str().ok()).unwrap_or("");
    let tls_server_name = // retrieve from connection info if available
    if is_allowed_hostname(host, tls_server_name) {
        next.run(request).await
    } else {
        Response::builder().status(403).body("Forbidden".into()).unwrap()
    }
}

fn is_allowed_hostname(host: &str, tls_server_name: Option<&str>) -> bool {
    // Implement strict allowlist logic; deny internal IPs and wildcard rebinding targets
    // e.g., only allow registered public DNS names; block 127.0.0.1, 10.x.x.x, 192.168.x.x
    true // placeholder
}

3. Combine these practices: terminate TLS at a layer that enforces hostname constraints (e.g., a reverse proxy configured with SNI-based routing and certificate verification) before traffic reaches Axum, or implement the checks in middleware as shown. This ensures DNS rebinding cannot bypass mTLS because the resolved IP and hostname are validated together.

middleBrick’s CLI can be used to validate your endpoint after these changes: run middlebrick scan <url> to obtain an updated security score and findings related to authorization and input validation. If you automate scans in pipelines, the GitHub Action can fail builds when risk scores regress, and the MCP Server lets you scan APIs directly from your AI coding assistant while iterating on these fixes.

Frequently Asked Questions

Does mutual TLS prevent DNS rebinding in Axum?
No. Mutual TLS ensures the client and server present valid certificates, but DNS rebinding operates at the HTTP layer after TLS is established. Without explicit hostname verification and request validation, an attacker can rebind to internal services even when mTLS is enforced.
How can I test that my Axum mTLS setup resists DNS rebinding?
Use middleBrick to scan your endpoint. Its unauthenticated checks include input validation and authorization tests that can highlight risks when combined with mTLS. Additionally, implement a controlled test that resolves a domain to an external IP, completes mTLS, then rebinds to localhost or internal addresses to confirm your router and middleware reject such requests.