To understand the leak, you have to understand a subtle requirement. When a resolver asks for a name that does not exist, the server needs to say "no" in a way that is cryptographically signed. Otherwise an attacker could forge a "this does not exist" answer to hide a record, or forge a fake record where a real "no" should be. DNSSEC calls this authenticated denial of existence, and it is genuinely necessary. The trouble is entirely in how the original design delivered it.
The NSEC record and the walk
A DNS zone can hold thousands of names. Signing a separate "this name does not exist" statement for every possible non-existent name is impossible, since there are infinitely many. The original solution, the NSEC record, is elegant. It sorts all the real names in the zone into canonical order and, for each one, publishes a signed record saying "the next existing name after this one is X." A gap between two names is a signed proof that nothing exists in between.
So if a resolver asks for a name that falls in a gap, the server returns the NSEC record covering that gap, which proves the name is absent. The proof is sound. It is also a linked list of your entire zone.
Ask for a name you know does not exist. The signed answer tells you the next name that does exist. Ask for a name just after that one, and the answer reveals the next name again. Repeat, and you follow the chain all the way around the zone, recovering every single name in it. Tools automate this in seconds. The feature that proves absence also enumerates presence.
For a public website this may not matter much. But zones routinely contain names their owners assumed were obscure: internal hostnames, staging servers, VPN endpoints, device names, and subdomains that reveal vendors or infrastructure. Zone enumeration turns "security by obscurity" for those names into no security at all, and it feeds directly into reconnaissance and attack surface mapping.
NSEC3: hashing the names
NSEC3, standardized in RFC 5155, was the response. Instead of listing the actual names in order, NSEC3 lists the cryptographic hashes of the names in order. The chain still proves absence, because the resolver can hash the queried name and check whether its hash falls in a signed gap. But an attacker walking the chain now recovers a list of hashes, not names. NSEC3 uses SHA-1 with a per-zone salt and a configurable number of hash iterations.
NSEC3 also added opt-out, a feature for large delegation-heavy zones like top-level domains that lets them skip signing denial for unsigned delegations, reducing the size of the signed zone. That is an operational optimization rather than a privacy feature.
Why hashing did not close the door
Here is the part that surprises people. Hashing the names raised the cost of enumeration, but it did not eliminate it. An attacker walks the NSEC3 chain to collect the full set of name hashes, takes that list offline, and then runs a dictionary or brute-force attack against it, exactly the way an attacker cracks a leaked password database. DNS names are short, use a small character set, and follow predictable patterns like www, mail, vpn, and dev, which makes them far easier to guess than passwords.
NSEC3 changed zone enumeration from a free lookup into an offline cracking problem. For a zone full of common, guessable names, that is a speed bump rather than a wall. Purpose-built crackers recover a large fraction of a typical zone's names on ordinary hardware. The uncomfortable result
Tools like nsec3walker and GPU-accelerated hash crackers reduced the practical protection further. The same weaknesses that make fast hashes bad for passwords apply here: SHA-1 is fast, so an attacker can try billions of candidate names quickly. Raising the iteration count slows the attacker, but it slows every legitimate resolver just as much, and it turns out not to help nearly as much as hoped.
The modern guidance: stop over-tuning NSEC3
For years the intuition was to crank up NSEC3 iterations for more protection. RFC 9276, published in 2022, reversed that advice with data behind it. Its recommendation is blunt: use zero extra iterations and an empty salt. The reasoning is that high iteration counts impose a real cost on validating resolvers and on the authoritative server, create denial-of-service risk, and buy almost nothing against a determined attacker who is going to crack guessable names regardless. If enumeration is your concern, iterations are the wrong lever.
| Approach | What an attacker gets | Note |
|---|---|---|
| NSEC | Every name, directly, in seconds | The original design; full enumeration is trivial |
| NSEC3 | Hashes to crack offline | A speed bump; guessable names still fall. Use 0 iterations per RFC 9276. |
| Compact denial (black lies) | Almost nothing | Server signs minimal on-the-fly answers; no walkable chain |
The approach that actually stops the walk
The technique that closes the door is sometimes called compact denial of existence, or by its informal name, black lies. Rather than publishing a static chain of what does not exist, the authoritative server generates a minimal signed answer on the fly for each non-existent query, claiming only that the exact queried name does not exist and covering the narrowest possible range around it. There is no chain to walk, because the "next name" pointer never reveals a real neighbor.
This requires online signing, meaning the private key material is used live at query time rather than to sign a static zone in advance. That is a meaningful operational trade-off, since it changes where and how key material is exposed. Large DNS operators that already run online signing, such as Cloudflare, adopted this approach, and the technique is being formalized in the IETF. For most zone owners, the practical answer is simpler: use NSEC3 with the RFC 9276 defaults, and do not rely on any DNS name staying secret.
The real lesson for defenders
The deepest takeaway is not about DNSSEC configuration. It is that DNS names were never a place to keep secrets. Certificate Transparency logs already publish the names on your TLS certificates. Passive DNS databases record names as they are queried in the wild. Zone enumeration is one more reason to assume that any hostname you create will become known. The right defense is to make sure knowing a name buys an attacker nothing, by putting real authentication and encryption behind it, which is the same reasoning behind zero-trust architecture.
Where Haven fits
Haven runs DNSSEC because authenticated DNS answers protect users from forged records that could redirect them to an impostor, and that protection is worth having. We treat our hostnames as public information rather than as a secret to guard, and we put strong authentication behind every name so that discovering one gains an attacker nothing useful. The broader principle is one we return to often: security should come from cryptography a user can verify, never from a detail that happened to be hard to find.