Dangling Dns in Axum with Mutual Tls
Dangling Dns in Axum with Mutual Tls — how this specific combination creates or exposes the vulnerability
A dangling DNS record occurs when a hostname (e.g., legacy.internal.example.com) still resolves to an IP, but the service that once used that hostname has been decommissioned or reconfigured. In an Axum service using mutual TLS (mTLS), a client presents a certificate that the server validates against a trusted CA. If the server’s identity is tied to a hostname that has a dangling DNS record, an attacker who can influence DNS (e.g., through a compromised registrar or an internal DHCP/DNS misconfiguration) may reassign that hostname to a malicious server. Because mTLS authenticates the server via its certificate, and the certificate may still include the dangling hostname as a Subject Alternative Name (SAN), a client that trusts that certificate could inadvertently route traffic to the attacker-controlled host. This is particularly risky when Axum services validate the server hostname strictly against the certificate without additional checks, effectively turning a DNS misconfiguration into a man-in-the-mesh opportunity despite mTLS.
With Axum, if your runtime configuration resolves a service endpoint by hostname and that hostname has a dangling DNS record, the client or proxy may establish a connection to an unexpected server. Even with mTLS enforcing channel-level authentication, the security assumption is that the server’s identity aligns with the intended network location. If the certificate presented by the malicious server carries the dangling hostname and is signed by a trusted CA, the client’s mTLS verification can pass while traffic is diverted. This scenario highlights that mTLS protects against on-path tampering but does not inherently prevent redirection caused by stale DNS data. The vulnerability is not in mTLS itself but in the interplay between certificate identities, hostname resolution, and DNS hygiene.
To detect this using middleBrick, you can scan your endpoint with the CLI: middlebrick scan https://api.example.com. The scan includes checks for unauthenticated endpoints and misconfigured identity mechanisms, which can surface mismatches between certificate SAN entries and active DNS resolution. In the context of LLM/AI Security, note that middleBrick uniquely probes for system prompt leakage and prompt injection, but for DNS and certificate alignment issues, rely on the standard authentication and endpoint configuration checks. The findings will include remediation guidance, such as removing unused DNS records and tightening certificate validation to explicitly verify intended hostnames.
Mutual Tls-Specific Remediation in Axum — concrete code fixes
Remediation focuses on ensuring that server certificates do not include dangling hostnames and that Axum clients validate the server hostname explicitly. On the server side, regenerate certificates to remove stale SAN entries and rotate keys if there is any risk of exposure. On the client side, use strict hostname verification regardless of mTLS. Below are concrete Axum examples that demonstrate a secure mTLS setup with explicit hostname checks.
First, a server configuration that loads a certificate chain and private key, ensuring only the intended hostname is present in the certificate:
use axum::Server;
use hyper_rustls::TlsAcceptor;
use std::sync::Arc;
use tokio::net::TcpListener;
async fn start_secure_server() {
let cert = rcgen::generate_simple_self_signed(vec!["api.example.com".to_string()]).unwrap();
let privkey = cert.serialize_private_key_der();
let cert_der = cert.serialize_der().unwrap();
let tls_acceptor = TlsAcceptor::from(Arc::new(
rustls::ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth() // mTLS would require client auth configuration here
.with_single_cert(vec![cert_der], rustls::PrivateKey(privkey))
.unwrap(),
));
let listener = TcpListener::bind("0.0.0.0:8443").await.unwrap();
let make_svc = axum::Router::new().into_make_service();
Server::builder(tls_acceptor.accept_stream(listener))
.serve(make_svc)
.await
.unwrap();
}
Second, a client configuration that verifies the server hostname explicitly, preventing redirection to a host with a dangling DNS record:
use axum::Client;
use hyper_rustls::HttpsConnector;
use hyper::client::HttpConnector;
use std::sync::Arc;
use rustls::{ClientConfig, RootCertStore, ServerName};
use webpki_roots::TLS_SERVER_ROOTS;
async fn secure_client_request() {
let mut root_store = RootCertStore::empty();
root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
let client_config = ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();
let https = HttpsConnector::from((HttpConnector::new(), Arc::new(client_config)));
let client = Client::builder().build::<_, hyper::Body>(https);
// Explicitly verify the hostname matches the certificate
let uri = "https://api.example.com/health".parse().unwrap();
let request = hyper::Request::builder()
.uri(uri)
.body(hyper::Body::empty())
.unwrap();
// Perform the request and ensure the response is validated
let response = client.request(request).await.unwrap();
// Additional logic can inspect the response status and headers
}
These examples ensure that server certificates are scoped to the intended hostname and that clients enforce hostname verification, mitigating the risk introduced by a dangling DNS record. middleBrick scans can help identify whether certificate SANs contain stale hostnames and whether endpoints are reachable under unexpected identities.