DNS 0x20: The Spoofing Fix Written in Random Capitals

In 2023 Google's resolver quietly started asking for wIKiPEDiA.oRG instead of wikipedia.org. It's not a bug — it's a 15-year-old anti-spoofing hack that never became a standard, works anyway, and shipped because it needs permission from absolutely no one.

If you sniffed the DNS traffic leaving Google’s public resolver in early 2023, you’d have seen something that looks like a bug. Queries going out for wIKiPEDiA.oRG. For GooGle.CoM. For eXamPLE.nET. Random, jagged capitalization, as if a cat had walked across the shift key. It wasn’t a bug. It was a defense — one first written down in 2008, never blessed as a standard, and switched on globally fifteen years later because it turned out to need cooperation from nobody at all.

The trick has an ugly name: DNS 0x20, or case randomization. It’s one of my favorite things in the whole protocol, because it’s a hack in the honest sense — it exploits an accident of how DNS was specified to buy real security, for free, without asking anyone’s permission. And the story of why it works is the story of why some security fixes spread and others rot in a draft.

The weakness it patches

Start where every DNS spoofing story starts: the summer of 2008, and Dan Kaminsky. A recursive resolver asking an authoritative server “what’s the address for example.com?” matches the answer to its question using a 16-bit transaction ID. Sixteen bits is 65,536 possibilities — a number that sounds large until you realize an off-path attacker, someone who can’t see your traffic and can only fire blind, can flood you with thousands of forged answers carrying guessed IDs, and if one lands before the real answer, they’ve poisoned your cache and can redirect a whole domain.

The fix everyone remembers is source port randomization. The query already carried a random 16-bit ID; now it also went out from a random source port, and the forger had to guess both. RFC 5452 wrote it down, resolvers shipped it, and roughly 32 bits of entropy replaced 16. Crisis managed.

But “managed” isn’t “solved.” Thirty-two bits of guessing is harder, not impossible, and none of it authenticates anything — it just makes the lottery more expensive to win. DNSSEC is the real authentication answer, signing records cryptographically, and twenty-odd years in most zones still aren’t signed because it demands a key-management commitment nobody wants. So the question in 2008 was: while we wait forever for DNSSEC, can we squeeze more entropy out of the query for free?

The accident in the spec

Here’s the accident. DNS names are case-insensitive: example.com, EXAMPLE.COM, and ExAmPlE.cOm all resolve to the same place. RFC 1035 said so in 1987. But — and this is the load-bearing detail — the case is preserved. When you ask an authoritative server about ExAmPlE.cOm, a well-behaved server treats the lookup as case-insensitive but echoes your question back in the answer exactly as you spelled it, mixed case and all. RFC 4343, published in 2006 with the deadpan title “Domain Name System (DNS) Case Insensitivity Clarification,” nailed down precisely this behavior.

Paul Vixie and David Dagon looked at that and saw free entropy. If the case comes back exactly as sent, then the case is a channel. Randomize it on the way out, and the attacker forging a reply now has to guess it too.

The name “0x20” is the mechanism in a nutshell. In ASCII, uppercase and lowercase letters differ by exactly one bit — the one with value 32, 0x20 in hex. A is 0x41, a is 0x61; flip that single bit and you flip the case. So a resolver walks the query name letter by letter and randomly toggles bit 0x20 on each one. Every alphabetic character becomes one more coin flip the attacker has to call correctly. A ten-letter domain adds about ten bits of entropy — stacked on top of the transaction ID and the random source port. The draft-vixie-dnsext-dns0x20 internet-draft laid it out in March 2008, right in the middle of the Kaminsky scramble.

Why it never became a standard

That draft expired. It has no formal standing in the IETF, and it never became an RFC. Normally that’s where a clever idea dies.

The reason 0x20 didn’t die is that it needs permission from nobody. Think about what it takes to deploy. Not a protocol negotiation, not a new record type, not a flag day, not the other end upgrading anything — it’s a resolver, on its own, sending queries it was always allowed to send, and checking that the answer’s case matches what it sent. The authoritative server doesn’t have to know 0x20 exists. It just has to do what RFC 4343 already told it to do: preserve case. If it does, the resolver gets free spoofing resistance. If some middlebox on the answer’s path rewrites the case, the resolver notices the mismatch and can fall back.

That “needs nobody’s cooperation” property is the whole difference between the fixes that spread and the ones that don’t. DNSSEC needs every zone owner to sign. DNS cookies, the other cheap anti-spoofing trick, need the authoritative side to enforce them, and enforcement mostly defaults to off. QNAME minimization, by contrast, was a pure resolver-side change that cost no one else anything — and it quietly spread until it was everywhere. 0x20 is in that lucky second category. There’s no committee to convince. You just do it.

And the measurements said you safely could. The Georgia Tech paper that accompanied the draft checked the real internet and found more than 99.7% of authoritative servers preserve mixed case correctly. The long tail that doesn’t — a sliver of stubborn load balancers and appliances that lowercase everything or, worse, return inconsistent case — is exactly why 0x20 can’t be made mandatory. Turn it on globally and force it, and you’d break resolution for that fraction of a percent. This is the same reason it stayed a hack: a standard has to work for everyone, but a hack only has to work for almost everyone, and degrade gracefully for the rest.

Turned on, quietly

So it sat there for years — implemented in Unbound as use-caps-for-id, off by default, with a per-domain exemption list for the servers that choke on it, deployed by operators willing to babysit the exceptions. A good idea with an asterisk.

Then in January 2023, Google Public DNS announced it had enabled case randomization across its resolvers. Today the large majority of the UDP queries Google’s resolver sends to authoritative servers go out in scrambled case. No standard drove that. No mandate. One of the largest resolvers on earth measured that the risk was tolerable and the benefit was free, and flipped the switch — and because the mechanism is unilateral, that single decision protects an enormous share of the world’s DNS lookups without anyone else lifting a finger.

I like 0x20 because it’s honest about what it is. It doesn’t pretend to be DNSSEC. It authenticates nothing; an on-path attacker who can see your queries reads the case right off the wire and the whole thing evaporates. It is, like source port randomization before it, a speed bump — more entropy, a harder lottery, nothing more. But it’s a speed bump that costs one bit per letter, needs zero coordination, and degrades to “no worse than before” when it fails. That combination is rare. Most security improvements demand that everyone else move first, and so they wait forever. This one just asked for the capital letters we were already allowed to use — and got fifteen years of free protection out of an accident in a 1987 spec.

Continue the conversation

← Back to Blog