HIGH dns cache poisoningaxummutual tls

Dns Cache Poisoning in Axum with Mutual Tls

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

DNS cache poisoning (also known as DNS spoofing) occurs when an attacker injects a malicious DNS response into a resolver’s cache, causing a victim to be directed to an attacker-controlled IP. In Axum applications that use mutual TLS (mTLS), the risk surface changes but does not disappear. mTLS ensures that both client and server present valid certificates during the TLS handshake, which prevents unauthorized parties from establishing a TLS connection with the server. However, mTLS does not protect the client’s DNS lookup before the connection is initiated.

When an Axum service running on Rust makes outbound HTTP or HTTPS requests, it typically relies on the system’s DNS resolver (for example, via the operating’s resolver or a library like hickory-resolver). If the resolver’s cache is poisoned, the domain name may resolve to an IP controlled by an attacker. Even with mTLS, the client will complete a TLS handshake with the attacker’s server if the attacker presents a certificate that is valid for the expected hostname (e.g., issued for the target domain). Because mTLS requires the client to trust the server’s certificate, a poisoned DNS record can redirect traffic to a malicious server that satisfies certificate validation, enabling man-in-the-middle (MITM) interception despite mTLS.

The combination of Axum and mTLS can therefore create a false sense of security. Developers may assume that mTLS alone prevents tampering, but DNS resolution happens before TLS, outside the scope of mTLS. Attackers can leverage vulnerabilities in DNS infrastructure, compromised recursive resolvers, or protocol weaknesses (such as lack of DNSSEC) to poison caches. Once the DNS is poisoned, any subsequent mTLS-secured requests from the Axum client to the poisoned domain will be directed to the attacker, who can then terminate TLS with a valid certificate and proxy or manipulate traffic.

To mitigate this, Axum-based applications must ensure DNS lookups are performed securely and are resistant to poisoning. This includes using DNS-over-HTTPS (DoH) or DNSSEC-validating resolvers, avoiding reliance on the local system’s vulnerable resolver, and validating server certificates strictly. MiddleBrick scans can detect whether an Axum service’s API calls are susceptible to DNS manipulation by checking for missing DNS validation controls and improper certificate verification practices.

Mutual Tls-Specific Remediation in Axum — concrete code fixes

Securing Axum clients against DNS cache poisoning in the context of mTLS requires hardening DNS resolution and certificate validation. Below are concrete code examples that demonstrate how to implement a DNSSEC-validating or DoH-based resolver and enforce strict certificate checks in an Axum-based Rust client.

1. Use a DNS-over-HTTPS (DoH) resolver to prevent cache poisoning

Instead of relying on the system DNS, perform DNS over HTTPS to obtain authoritative records. This example uses the trust-dns-resolver crate configured with a DoH provider.

use trust_dns_resolver::config::{ResolverConfig, ResolverOpts, NameServerConfigGroup};
use trust_dns_resolver::Resolver;
use std::sync::Arc;

// Configure DoH (using Cloudflare as an example)
let mut opts = ResolverOpts::default();
opts.attempts = 2;
opts.timeout = std::time::Duration::from_secs(5);

let https_client = reqwest::Client::new();
let mut config = ResolverConfig::new();
// Add a DoH name server
config.add_doh_mtls(
    "cloudflare",
    "https://cloudflare-dns.com/dns-query",
    &mut trust_dns_proto::op::Message::new(),
)?;

let resolver = Arc::new(Resolver::new(config, opts)?);
// Use resolver.lookup_ip("api.example.com") to obtain IPs securely

This approach ensures DNS responses are authenticated and integrity-protected, reducing the risk of cache poisoning.

2. Enforce strict certificate validation in Axum client requests

When making outbound mTLS requests from Axum, pin the server certificate or public key and verify the hostname explicitly. The following example uses reqwest with a custom certificate and hostname verification.

use reqwest::Client;
use std::fs;

// Load client certificate and private key for mTLS
let cert = fs::read("client.crt")?;
let key = fs::read("client.key")?;
let identity = reqwest::Identity::from_pkcs8_pem(&format!("-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\ncertificate content"))?;

// Build a client with pinned server certificate
let ca_cert = fs::read("server-ca.crt")?;
let mut builder = Client::builder()
    .identity(identity)
    .add_root_certificate(reqwest::Certificate::from_pem(&ca_cert)?);

// Enforce hostname verification (enabled by default in reqwest)
let client = builder.build()?;

// Example request to a domain resolved via secure DNS
let response = client.get("https://api.example.com/health").send().await?;

Ensure that certificate validation is not disabled (e.g., avoid .danger_accept_invalid_certs) and that hostname checks are enforced. Combine this with secure DNS resolution to mitigate DNS cache poisoning risks in mTLS deployments.

Frequently Asked Questions

Does mutual TLS prevent DNS cache poisoning?
No. Mutual TLS secures the TLS channel after a DNS lookup, but it does not protect the DNS resolution step. If an attacker poisons the DNS cache, mTLS can be bypassed if the attacker presents a valid certificate for the expected hostname.
How can I detect DNS cache poisoning risks in my Axum API scans?
Use MiddleBrick scans, which check for insecure DNS resolution practices and missing DNSSEC or DoH controls. The scan report will highlight whether your Axum service relies on vulnerable resolvers and whether certificate validation is properly enforced.