DNS Poisoning (Cache Poisoning / Spoofing)
Also known as: DNS cache poisoning, DNS spoofing, Resolver cache poisoning
A condition where a DNS resolver accepts and caches a forged answer, so users and systems asking for a known name are silently sent to the wrong host.
How it works
DNS poisoning happens when a resolver stores a DNS answer that did not come from the authoritative source, so later queries for that name return the wrong address until the entry expires. Users type the right name and still land on the wrong host.
Classic DNS is unauthenticated. A resolver accepts a response if it matches the question it asked, so the strength of that match, such as the query ID, the source port and the name's letter case, is what stands between a genuine answer and a forged one. Weak randomness, open recursion and unvalidated data widen the gap.
The impact depends on what the name guards. A wrong address for a login portal, update server or mail host can redirect credentials, software downloads or mail, and a cached forgery affects every client of that resolver until the TTL runs out.
Defence is layered. Validate answers cryptographically with DNSSEC, randomize query IDs and source ports, use 0x20 case encoding, limit who may use recursion, separate caching from authoritative roles, keep resolver software current, and watch logs for answers that disagree with what you know to be true.
Walk through it
- 1Spot the anomalous answer
- 2Review the resolver settings
- 3Choose the preventive control
- Scope who was affected
- Flush, validate and monitor
Your internal resolver log for the company's own portal shows several answers. One of them returns an address that does not belong to the portal's known range, and it arrived with an unusually long TTL. Type the address you would escalate.
Answers for portal.contoso.example, last 15 minutes
09:02:10 portal.contoso.example A 198.51.100.20 TTL 300 rcode=NOERROR
09:04:41 portal.contoso.example A 198.51.100.20 TTL 300 rcode=NOERROR
09:06:03 portal.contoso.example A 203.0.113.66 TTL 86400 rcode=NOERROR
09:07:55 portal.contoso.example A 203.0.113.66 TTL 86400 rcode=NOERROR
Known good range for this portal: 198.51.100.0/24
Spot it
- A known internal or business-critical name resolving to an address outside its documented range.
- Answers with unusually long TTLs for names that normally use short ones.
- Duplicate or conflicting responses for a single query, or responses that arrive with mismatched query IDs or source ports.
- A sudden spike in queries or in SERVFAIL and validation failures for one signed zone.
- Clients reporting certificate warnings on a site whose name looks correct, while the resolved address changed.
Resolver query log
ts=2026-10-11T09:02:10Z client=10.20.4.31 qname=portal.contoso.example qtype=A answer=198.51.100.20 ttl=300
ts=2026-10-11T09:06:03Z client=10.20.4.52 qname=portal.contoso.example qtype=A answer=203.0.113.66 ttl=86400Resolver validation log
ts=2026-10-11T09:06:03Z zone=contoso.example validation=failed reason=no-valid-signature action=discardedsplSplunk, known names answered outside their expected range
index=dns sourcetype=resolver qtype=A qname IN (portal.contoso.example, mail.contoso.example)
| where NOT cidrmatch("198.51.100.0/24", answer)
| stats count min(ttl) max(ttl) by qname, answer, clientMaintain the expected-range list as data, and alert when a protected name returns anything else.
kqlKQL, long-TTL answers for names that normally use short TTLs
DnsEvents
| where Name endswith "contoso.example" and QueryType == "A" and TimeToLive > 3600
| summarize count() by Name, IPAddresses, ClientIPStop it
Validate answers with DNSSEC
Sign your zones and run validating resolvers so unsigned or altered data for a signed name is rejected rather than cached. This is the control that proves authenticity instead of relying on guesswork.
Make forged responses hard to match
Randomize query IDs and source ports, add 0x20 case randomization, and keep resolver software patched, so an off-path party cannot reliably construct a response the resolver will accept.
Shrink exposure and watch it
Restrict recursion to your own clients, separate caching and authoritative roles, use encrypted transport (DoT or DoH) to trusted resolvers, and alert on protected names that answer outside their known ranges.
Restricted, validating resolver
Vulnerable
recursion yes;
allow-recursion { any; };
dnssec-validation no;Hardened
recursion yes;
allow-recursion { 10.20.0.0/16; };
dnssec-validation auto;
rate-limit { responses-per-second 10; };Adapt directive names to your resolver. The point is scope, validation and rate limiting.
- Enable DNSSEC validation on every recursive resolver and sign zones you own.
- Restrict recursion to internal client ranges and disable it on authoritative servers.
- Use random source ports and query IDs, and enable 0x20 case randomization where supported.
- Send client queries to trusted resolvers over DoT or DoH where your policy allows.
- Keep resolver software patched and cap cache TTLs for protected names.
- Alert on protected names answering outside their documented ranges.
If it already happened
Flush the affected cache entries, block the rogue address at the egress firewall, and temporarily point clients at a validating resolver.
Identify how the resolver accepted the forged data, then restrict recursion, enable validation and patch the resolver. Check whether credentials were entered on the wrong host and reset them.
Confirm protected names resolve to their documented ranges, validation failures are zero for legitimate zones, and caches hold only genuine data.
Add the answer-range and long-TTL detections permanently, sign remaining zones, and review which services lacked certificate or pinning checks that would have exposed the wrong host.
Check yourself
1. What makes a poisoned DNS cache entry harmful to many users at once?
2. Which log observation is the strongest indicator of DNS poisoning against a known internal portal?
3. Which control gives cryptographic proof that a DNS answer came from the zone owner?