Here’s a thing about DNSSEC that sounds like a joke but isn’t: the mechanism that proves a name doesn’t exist will happily hand an attacker the list of every name that does. You sign your zone to make it trustworthy, and one of the things you get for free is a machine-readable index of your entire internal namespace — every subdomain, every host you forgot was there. People have been walking zones this way for fifteen years. NSEC3 was the fix. It didn’t fix it.
To see why, you have to sit with the problem DNSSEC was actually solving, because it’s genuinely hard and the failure comes straight out of the hard part.
You can’t sign a promise you didn’t make in advance
DNSSEC signs records with keys that live offline, away from the servers answering queries. That’s the whole security model — the signing key isn’t sitting on an internet-facing box waiting to be stolen. Great for the records that exist: you sign www.example.com once, ahead of time, and every resolver can verify it forever.
Now someone queries does-not-exist.example.com. The honest answer is “no such name.” But an unsigned “no such name” is worthless — any attacker on the path could forge it to hide a record that does exist. So you have to sign the denial. And you can’t, because you didn’t know in advance which nonexistent name someone would ask about, and your signing key is offline so you can’t sign it on the spot.
The NSEC record (RFC 4034) is the clever, offline answer. Instead of signing “does-not-exist doesn’t exist,” you pre-sign statements about the gaps between the names that do exist. Sort every name in the zone alphabetically. For each one, sign a record saying “the next name after mail.example.com is www.example.com.” When a query comes in for does-not-exist, you return the signed gap that surrounds it — “nothing exists between mail and www” — and since does-not-exist falls in that gap, the resolver has cryptographic proof of absence. You signed it all ahead of time, offline. Elegant.
And also, obviously, a linked list of your entire zone. Ask for a gap, read the “next” name, ask for the gap after that name, read the next one, repeat. In a few hundred queries you’ve enumerated a zone that returns NXDOMAIN to every direct guess. This is zone walking, and it’s not a clever exploit — it’s just following the pointers DNSSEC signed for you. The tooling is a one-liner.
NSEC3: hash the names, hope nobody cracks them
The 2008 response was NSEC3 (RFC 5155). Same linked-list trick, but instead of chaining plaintext names, you chain hashes of them. The record now says “nothing exists between hash a1b2… and hash c3d4….” Walk the chain and you collect a pile of hashes instead of a pile of hostnames. The names themselves stay hidden. Problem solved.
Except the hashes are of hostnames, and hostnames are terrible secrets. They’re short, they’re words, they follow patterns — vpn, mail, dev, staging, gitlab, admin, test-01. The NSEC3 hash is iterated SHA-1 over the name plus a salt, and once you’ve collected the hashes by walking the chain, you take them offline and crack them exactly like a leaked password file. Feed them to a dictionary, feed them to hashcat (it has a dedicated NSEC3 mode), feed them to nsec3walker — the tool Dan Bernstein published to make the point, which chewed through on the order of 2³⁴ guesses a day on a 2011 laptop. Against a namespace of common words, that’s not a brute-force problem, it’s a lookup. RFC 5155 admits this in its own security section: NSEC3 raises the cost of enumeration, it does not prevent it.
So the honest summary of NSEC3 is: it converts “read my zone directly” into “crack my zone offline,” and for the ordinary zone full of guessable hostnames, that conversion buys you almost nothing.
The iterations trap, and a standards body quietly admitting defeat
Here’s where it gets a little embarrassing. NSEC3 has an iterations parameter — how many times to re-hash. The intuition everyone reached for is the password-hashing intuition: more iterations, more expensive to crack, more secure. So zones cranked it up. Hundreds of iterations, on the theory that they were slowing attackers down.
They weren’t slowing attackers down in any way that mattered — offline cracking of low-entropy names is cheap at any iteration count you’d dare deploy. What they were doing is making every validating resolver on the internet redo all those hashes on every negative answer. That’s not the attacker’s cost, it’s the defender’s, and it’s paid by the resolvers, which means it’s a denial-of-service amplifier pointed at the DNS itself.
RFC 9276, published in 2022, is the standards process walking this back as bluntly as these documents ever do. The guidance: iterations MUST be 0. Salt SHOULD be empty. Zero extra hashing, no salt. The reasoning, stated plainly, is that additional iterations provide no meaningful protection against enumeration while adding CPU load and interoperability breakage — resolvers had already started treating high-iteration zones as insecure, or returning SERVFAIL outright, to protect themselves. When the fix for your anti-enumeration feature is “turn the anti-enumeration knob to zero because it never worked and it’s hurting us,” the feature has lost the argument. Researchers summarized the new normal as “zeros are heroes.” An anti-enumeration mechanism whose official best practice is to disable its only tunable defense is telling you something.
What actually works
There are two honest positions, and cranking NSEC3 iterations is neither.
The first is to stop pretending. Your zone contents are, for most purposes, public. Certificate Transparency logs already publish every hostname you get a TLS certificate for — that ship sailed years ago. So don’t put secrets in DNS names, don’t assume an unlisted subdomain is hidden, and treat zone contents as discoverable. If that’s your threat model, plain NSEC with iterations-zero NSEC3 is fine, and you’ve saved yourself a lot of theater.
The second is to actually solve it, which requires giving up the thing that made the problem hard in the first place: offline signing. If your keys are online — at the edge, signing responses on demand — you can answer each nonexistent query with a freshly minted, minimal proof instead of a pre-signed gap between real names. This is compact denial of existence, originally floated as “black lies” by Filippo Valsorda at Cloudflare and standardized in 2025 as RFC 9824. The server returns a single NSEC record covering just the queried name, claiming it exists but has no records of that type. One record, no “next name,” nothing to walk, nothing to collect and crack. Cloudflare, NS1, and Amazon Route 53 all run some version of it. The price is real — your signing keys are now on internet-facing machines, which is exactly the risk offline signing existed to avoid — but for a large managed DNS operator with an HSM at the edge, it’s a price worth paying, and it makes zone walking simply stop working.
There was a third path, NSEC5 — an academic design using a verifiable random function to get provable enumeration resistance without fully trusting the online server. It’s cryptographically lovely and it never shipped. DNS doesn’t adopt new cryptographic primitives for problems most operators have decided they don’t have.
The uncomfortable takeaway
DNSSEC’s authenticated denial of existence is a genuinely elegant solution to a genuinely hard problem, and its very elegance — pre-signing everything offline — is what makes your zone walkable. NSEC3 was the industry spending a decade and a lot of CPU cycles to hash the problem instead of solve it, and RFC 9276 is the receipt: turn the defense off, it never worked. The move that actually stops zone walking, compact denial, works precisely because it abandons the offline-signing constraint that created the whole mess.
So before you reach for NSEC3 iterations to “hide” your zone, ask the question the standard is now implicitly asking you: hide it from whom, and do you actually believe you can? If the answer is a managed provider with online keys, you’ve already got the real fix. If it’s an offline-signed zone full of dev and staging and admin, the hashes are a formality. Somebody with a laptop and a wordlist is reading them tonight.