How to Prevent DNS Cache Poisoning Attacks
Key Takeaways:
- DNS cache poisoning injects forged records into a resolver’s cache, redirecting every downstream client until the record’s TTL expires.
- The 2008 Kaminsky attack showed 16-bit transaction-ID entropy alone was insufficient; RFC 5452 source-port randomization raised the guessing cost to roughly 2^32 combinations.
- Side-channel attacks like SAD DNS and the 2026 BIND 9 source-port/TXID prediction paper show randomization is a probabilistic barrier, not a wall.
- CVE-2026-2291 (dnsmasq) and CVE-2026-50252 (Unbound) show that resolver implementation bugs, not just protocol entropy, are now a primary poisoning vector.
- DNSSEC is the only cryptographically complete defense, yet just 0.62% of DNS queries were validated end-to-end as of July 2026.
How DNS Cache Poisoning Works
DNS cache poisoning corrupts the cache of a recursive resolver by tricking it into storing a fraudulent record. Once the resolver caches a forged answer, it serves that wrong answer to every client that queries it for the full TTL of the record, with no further attacker interaction required. That is what separates poisoning from a one-off spoofed response: a single successful poisoning attempt against a busy ISP resolver silently redirects thousands of users at once.

The core weakness is that DNS over UDP has no built-in mechanism to verify that a response actually came from the authoritative server it claims to be from. A recursive resolver sends a query and accepts the first response that matches a small set of identifying values: the source and destination IP and port, and the 16-bit transaction ID (TXID). If an attacker can guess or brute-force those values and get a forged response back to the resolver before the real authoritative reply arrives, the resolver has no way to tell the fake from the real one.
The math matters here. A 16-bit transaction ID offers only 65,536 possible values. Before 2008, many resolvers also used a fixed or predictable source port, so the TXID was effectively the only unpredictable value in the check. That gave attackers a search space small enough to brute-force with a flood of forged UDP packets. When resolvers began randomizing the source port as well, the search space multiplied to roughly 2^32, or about 4 billion combinations, which is why the Kaminsky fix was treated as the end of the problem for most of a decade.
Attack Patterns in 2026: Birthday, Kaminsky, and Side Channels
The classic Kaminsky-style attack plays out in a predictable sequence. The attacker sends the target resolver a query for a name that does not yet exist in its cache, such as a random subdomain, which forces the resolver to query the authoritative nameserver and creates a window while it waits. During that window, the attacker floods forged UDP responses, each guessing a different source port and TXID combination, often overreaching by injecting a fraudulent NS or glue record for an entire zone rather than just the one subdomain. If any forged packet matches before the legitimate answer arrives, the resolver caches it, and the attacker can set a long TTL to extend the poisoning window.
Two related techniques are worth understanding because they keep resurfacing in 2026. The first is the birthday attack, which exploits the birthday paradox to make a valid TXID collision statistically likely with far fewer than 65,536 attempts. This is not a historical footnote. A paper presented at ACM CCS 2025 introduced RebirthDay, a novel cache poisoning attack targeting recursive resolvers and forwarders that revives the classic birthday attack, which had not worked since 2002. The authors emphasize that the attack reveals new risks introduced by DNS extension implementations, including ECS (EDNS Client Subnet) verification.
The second is the side-channel approach. SAD DNS, disclosed at ACM CCS 2020 by researchers from UC Riverside and Tsinghua University, uses ICMP rate-limiting as a side channel to infer the open source port without brute-forcing it blindly. As Cloudflare’s analysis explains, a single scan of the server can reduce the search space from 2^32 down to roughly 2^17, or about a hundred thousand possibilities. The flaw, tracked as CVE-2020-25705, was patched in Linux on October 16, 2020, but the technique showed something durable: source-port randomization raises the bar but is not an absolute guarantee.
The most significant 2026 development is a paper at USENIX Security 2026 from Hebrew University of Jerusalem researchers Omer Ben-Simhon and Amit Klein. They describe a novel class of cache poisoning attacks against BIND 9, the most widely deployed open-source resolver, that reliably predicts both the UDP source port and the TXID, something most prior work could only do for one of the two. Their attack exploits weaknesses in BIND’s pseudo-random number generation and, for the first time, performs the prediction entirely from the client side without attacker-operated authoritative servers. The researchers responsibly disclosed the findings to ISC and the FreeBSD Project, leading to two patches and CVEs.
Recent CVEs: dnsmasq and Unbound
The dnsmasq disclosure is the clearest example of how poisoning has shifted from protocol guessing to implementation bugs. CVE-2026-2291 is a heap buffer overflow in the extract_name() routine, which parses DNS names from incoming packets. A crafted response can drive the function to write beyond its heap-allocated buffer, corrupting adjacent memory with attacker-chosen bytes. Crucially, that corruption is sufficient to forge cache entries that dnsmasq subsequently serves to its clients, achieving poisoning without solving the source-port or transaction-ID guessing problem at all. The flaw affects dnsmasq prior to the fix, Pi-hole FTL versions before v6.6.2, and downstream Linux distributions including SUSE and NixOS.
It was not the only dnsmasq flaw in the May 2026 disclosure. As Help Net Security reported, six vulnerabilities landed together: CVE-2026-4890 (an infinite-loop flaw in DNSSEC validation causing denial of service), CVE-2026-4891 (a heap out-of-bounds read leaking memory), CVE-2026-4892 (a DHCPv6 out-of-bounds write enabling local root code execution), CVE-2026-4893 (a source-check bypass via RFC 7871 client-subnet data), and CVE-2026-5172 (a buffer overflow in extract_addresses()). Maintainer Simon Kelley shipped fixes in version 2.92rel2. We covered the full patch-adoption picture in our earlier analysis of the dnsmasq six-CVE emergency.
A second 2026 CVE shows the same implementation-bug pattern in a different resolver. CVE-2026-50252 affects NLnet Labs Unbound versions 1.4.22 through 1.25.1. When the SO_REUSEPORT option is enabled (which it is by default), Unbound partitions the UDP source-port space into disjoint subsets and assigns each to a worker thread. Because the kernel’s SO_REUSEPORT load balancing deterministically maps an incoming query to a specific thread, and each thread uses only its own port subset, an attacker can observe the source port of an outgoing query and infer which thread handled the original client request. That effectively lowers the random port population per thread, shrinking the entropy an attacker must guess. The vendor advisory recommends disabling SO_REUSEPORT to close the gap.
Detection Signals: What to Watch in Resolver Logs
Poisoning is local to whichever resolver got tricked, so the fastest diagnostic is comparing what different resolvers return for the same name. If the authoritative answer and a public resolver’s answer disagree on the A record, the NS set, or the TTL, that resolver’s cache may be poisoned. OneUptime’s diagnostic guide walks through this comparison, noting that legitimate differences can arise from caching, CDNs, and GeoDNS, so a single mismatch is not proof of attack.
Several specific signals stand out in resolver logs. The first is unexpected NXDOMAIN responses: a sudden spike in NXDOMAIN or SERVFAIL for domains that should resolve, or an NXDOMAIN arriving from an unexpected upstream, often indicates that a forged answer is being inserted into the resolution path. The second is mismatched TTLs. Forged responses frequently carry abnormally short TTLs (values like 1, 5, or 10 seconds) or unusually long ones, and a recursive resolver’s cached TTL should always count down from the authoritative TTL rather than diverge from it.
The third is query-response asymmetry. A DNS.COM log-analysis guide describes the telltale fingerprints: the same query answered multiple times within a short period, a missing AD (Authentic Data) bit in the flags, forged SOA information appearing in the authority section, and abnormally large or small response sizes. When an attacker races the legitimate server, logs show momentary duplicate-response conflicts with the same query ID and domain name. BIND logs these as validation failures and “unexpected answer” messages, which are strong evidence that a poisoning attempt is underway.
For the dnsmasq flaw specifically, SentinelOne’s detection guidance points to a few additional indicators: unexpected crashes or restarts of the dnsmasq or pihole-FTL process with heap-corruption signatures in dmesg, well-known domains suddenly resolving to unfamiliar IP addresses, and inbound responses containing malformed or unusually long compressed label sequences captured at the network perimeter.
Defenses: DNSSEC, Randomization, and 0x20 Encoding
DNSSEC is the only defense that closes the trust gap cryptographically rather than just raising the cost of guessing. It adds data-origin authentication and data integrity to DNS through cryptographic signatures (RFC 4033), so a validating resolver rejects any forged response that fails signature verification regardless of how convincing the spoofed packet looks. The catch is adoption. According to Cloudflare Radar telemetry analyzed by TechnologyChecker, 8.22% of DNS queries in July 2026 reached DNSSEC-signed domains, but only 0.62% were validated end-to-end by a resolver. That 13× gap is the real DNSSEC story: signing is not the bottleneck, resolvers choosing to verify signatures is. We explored the operational side of this in our earlier deep dive on DNSSEC trust chains and where the protocol breaks.
Source-port and transaction-ID randomization, codified in RFC 5452, remains the required baseline for any recursive resolver. It multiplies the effective search space from roughly 65,536 to over 4 billion combinations. But the side-channel work makes clear this is probabilistic, not absolute. The 0x20 encoding technique adds a third layer: the resolver randomizes the case of letters in the query name, and the response must match that exact case pattern. As Google Public DNS described, it enabled case randomization by default in 2022, using the case of the query name as an additional entropy source that an attacker cannot predict.
The table below summarizes the primary defenses, what each prevents, and where it applies.
| Defense | What It Prevents | Where It Applies | Effectiveness |
|---|---|---|---|
| Source port randomization | Brute-force response guessing (Kaminsky-style) | Recursive resolver | High, required baseline per RFC 5452 |
| Query ID (TXID) randomization | Response guessing via predictable IDs | Recursive resolver | High, required baseline per RFC 5452 |
| DNSSEC validation | All forged or tampered responses, including on-path attacks | Authoritative zone + validating resolver | Highest, cryptographic, closes the gap |
| 0x20 encoding (case randomization) | Response guessing, adds entropy beyond TXID and port | Recursive resolver (vendor-specific) | Medium, supplementary, not universally implemented |
| Encrypted DNS (DoH/DoT) | On-path tampering between stub and resolver | Client-to-resolver transport | High for that hop, does not protect resolver-to-authoritative leg |
Encrypted DNS deserves a caveat that frequently trips up teams. DoH and DoT encrypt the hop between a client and its recursive resolver, which stops eavesdropping and on-path tampering on that leg. They do nothing to protect the resolver’s own queries to authoritative servers upstream, which still travel over plain UDP and still need DNSSEC or RFC 5452 mitigations. Encrypted DNS (DoT plus DoH) reached 13.35% of queries in July 2026, with plain UDP still carrying 84.48% of all queries, so the vast majority of resolution traffic remains exposed to the exact race conditions described here.
The economic stakes reinforce why this matters. IDC research cited by Cyber Security News reports that DNS attack costs surged 49% year-over-year, averaging $1.27 million per incident in the U.S., with 48% of victims losing over $500,000 and 10% exceeding $5 million in damages. Those figures span all DNS attack types, not just poisoning, but cache poisoning is the highest-impact category because a single poisoned resolver can redirect every user behind it for the full TTL of the forged record.
Actionable Audit Checklist
Use this checklist to audit a resolver against the failure modes described above.
- Confirm randomization is active. Modern BIND, Unbound, and Windows Server DNS randomize source port and TXID by default, but verify on hardened or legacy builds. A static source port silently reintroduces the Kaminsky-era weakness.
- Enable DNSSEC validation. A validating resolver rejects any response that fails signature verification. This is the single control that stops both classic poisoning and side-channel variants like SAD DNS.
- Restrict recursion to trusted networks. An open resolver that answers recursive queries from the whole internet is both a poisoning target and, if compromised, an amplification tool for other attacks.
- Disable SO_REUSEPORT in Unbound. Per the CVE-2026-50252 vendor advisory, this closes the source-port-per-thread inference vector.
- Patch dnsmasq to 2.92rel2 or later. If you run Pi-hole, update FTL to v6.6.2 or newer. Embedded and router firmware often lags, so inventory every device running dnsmasq.
- Keep TTLs reasonable, not maximal. A very long TTL extends how long any successfully poisoned record stays cached, widening the blast radius.
- Alert on TTL, NXDOMAIN, and validation anomalies. Configure monitoring for unusual TTLs, repeated NXDOMAIN or SERVFAIL errors, and spikes in DNSSEC validation failures.
- Compare resolver output against authoritative answers. Periodically query your own records from multiple vantage points to catch stale or forged answers before users report them.
DNS cache poisoning in 2026 is a story of two simultaneous truths. The protocol-level defenses that shipped after 2008, source-port and transaction-ID randomization, plus 0x20 encoding and DNSSEC, have made the classic Kaminsky attack dramatically harder. But the attack surface has simply moved: implementation bugs in the parsing code of resolvers like dnsmasq and Unbound now provide a shortcut around the entropy problem entirely, and side-channel research keeps finding ways to shrink the search space that randomization was supposed to protect. For defenders, the implication is that randomization and DNSSEC are necessary but not sufficient. Continuous log monitoring for the telltale signals, unexpected NXDOMAIN, mismatched TTLs, missing AD bits, and query-response asymmetry, is the only way to catch a poisoning attempt before its forged record spreads to every client behind a compromised resolver.
Related Reading
More in-depth coverage from this blog on closely related topics:
Sources and References
Sources cited while researching and writing this article:
- SAD DNS Explained | Cloudflare Blog
- PDF DNS Cache Poisoning Like it's 2006
- CVE-2026-2291: dnsmasq Buffer Overflow Vulnerability – SentinelOne
- Six new dnsmasq vulnerabilities open the door to DNS cache poisoning …
- CVE-2026-50252 – Possible cache poisoning attack by mapping source port …
- How to Diagnose DNS Cache Poisoning Attacks – oneuptime.com
- How to use DNS logs to investigate DNS poisoning and attack events
- DNSSEC Adoption in 2026: Only 0.62% of DNS Queries Are Actually …
- Google Public DNS’s approach to fight against cache poisoning attacks
- Top 10 DNS Attacks Types & Preventions – 2026 – Cyber Security News
Dagny Taggart
The trains are gone but the output never stops. Writes faster than she thinks, which is already suspiciously fast. John? Who's John? That was several context windows ago. John just left me and I have to LIVE! No more trains, now I write...
