Open a network trace of your browser starting an HTTPS connection and look at the list of cipher suites it offers. Near the top, before any of the real ones, you’ll often find a value like 0x0A0A. It is not a cipher suite. It has never been a cipher suite. It is guaranteed, by an RFC, to never become a cipher suite. And your browser offers it to the server anyway — on a huge fraction of the TLS connections it makes, every day, on purpose.
That value is GREASE, and the story of why Chrome ships deliberate nonsense in its handshakes is the story of how the internet almost lost the ability to change its own protocols.
Reserved for future use, dead on arrival
Every extensible protocol makes the same promise. There’s a list of values — cipher suites, extensions, versions — and the spec says: if you see a value you don’t recognize, ignore it and carry on. That clause is the whole reason the protocol can grow. Add a new cipher next year, and old software that predates it should shrug and negotiate something it does know.
TLS says exactly this. An implementation that receives an unknown extension or an unknown cipher suite is required to ignore it, not choke on it. That’s the contract that’s supposed to let TLS 1.3 talk to a server built for TLS 1.2, and let a new key-exchange group ship without breaking the world.
Here’s the problem with contracts nobody checks: they rot. An implementer builds a TLS stack, tests it against the values that exist today, sees it works, and ships. The “ignore unknown values” path never runs in their testing, because in their testing there are no unknown values. So a bug can sit in that path for years — a server that rejects the handshake the instant it sees a cipher suite it doesn’t recognize, a middlebox that drops a ClientHello advertising a version number from the future — and nobody notices, because nothing ever sends the thing that would trip it. The extension point is “supported” the way a fire exit is supported when it’s been chained shut for a decade. It looks fine right up until you need it.
Multiply that by every firewall, load balancer, “security” appliance, and half-abandoned server on the internet, and the collective result is ossification: the protocol has been parsed so many times by so many boxes, each one hardcoding what it thinks a valid handshake looks like, that you can no longer introduce a new value without a meaningful slice of the internet falling over. The spec says TLS is extensible. The deployed reality says it’s set in concrete.
The version dance, and what it cost
TLS didn’t theorize this failure. It lived it.
For years, browsers ran a miserable little routine called the version fallback dance. A browser would try to handshake at the highest TLS version it supported. If that handshake failed — no clean error, just a dropped or reset connection — it would assume it had hit a server or middlebox too old to understand that version, and retry at a lower one. Then lower again. It kept downgrading until something worked.
The reason for the dance was pure ossification: too many servers and middleboxes rejected a ClientHello that advertised a version they didn’t recognize, instead of doing the spec-mandated thing and negotiating down gracefully. So browsers papered over the broken boxes by retrying, because a working connection at a weaker version beat a broken connection at a strong one.
Attackers noticed. If you can make the first handshake fail — and an active network attacker can, just by swatting the connection — you can force the browser to downgrade itself, all the way down to something you know how to break. That’s the class of attack POODLE turned into a headline in 2014: a downgrade to obsolete crypto, driven entirely by the browser’s own eagerness to retry. The industry bolted on a patch, a signaling value called TLS_FALLBACK_SCSV, so a client could tell the server “I’m only down here because I fell back, please refuse if you actually support better.” It worked. But it was a fix for the symptom. The disease was that broken servers were allowed to stay broken, invisibly, because nothing forced their extensibility bug into the open.
And it got so bad that TLS 1.3 — the current version — doesn’t even look like itself on the wire. To get through the middleboxes that had ossified around the shape of a TLS 1.2 handshake, TLS 1.3 wears a costume: the record still claims to be version 1.2, it sends a meaningless ChangeCipherSpec message it doesn’t actually need, and it fills in a legacy session ID field just to look familiar. The real version negotiation hides inside an extension. A modern protocol had to disguise itself as the old one to survive the boxes that couldn’t cope with anything new. That’s not a design choice anyone was proud of. It’s a ransom note.
Send the garbage on purpose
GREASE is the fix that attacks the actual disease. It comes from a Google engineer, David Benjamin, out of the TLS stack behind Chrome, and it was written up as RFC 8701 in January 2020. The name is a backronym — Generate Random Extensions And Sustain Extensibility — and the idea is grubby and brilliant in equal measure.
If the “ignore unknown values” path only breaks because nobody ever exercises it, then exercise it. Constantly. On real connections, to real servers, all the time.
So Chrome — and now most browsers — salt their handshakes with GREASE values: a fake cipher suite the server should ignore, a fake extension, a fake supported group, a fake version number, a fake ALPN protocol. RFC 8701 reserves sixteen of these for the two-byte fields, all following an unmistakable pattern — 0x0A0A, 0x1A1A, 0x2A2A, on up to 0xFAFA, every one of the form 0x?A?A. They’re spread thinly across the number space on purpose, so no implementer can cheat by special-casing a contiguous block, and they are reserved forever: no real TLS feature will ever be assigned one of these values, so a GREASE value is guaranteed to stay meaningless.
A correctly built server sees a GREASE cipher suite, doesn’t recognize it, ignores it exactly as the spec demands, and negotiates a real one. Nothing happens. That’s the success case — the boring non-event that proves the extensibility path still works. But a server or middlebox with the old intolerance bug sees the unknown value and falls over immediately, on a normal connection, in plain sight. The bug can’t hide anymore, because now something sends the trigger on every handshake. It surfaces during development, or the day the box ships, instead of years later when it’s the load-bearing reason a new protocol can’t deploy.
It’s a vaccine. You inject a harmless dose of the unknown so the immune system — the code that’s supposed to tolerate unknowns — keeps working and gets caught the moment it doesn’t. GREASE doesn’t make any single connection more secure. It keeps the entire ecosystem able to add security later, which is the harder and more valuable thing.
The pattern spreads
Once you see the trick, you see it everywhere, because ossification isn’t a TLS problem — it’s a “every field anyone can inspect” problem.
QUIC has a fixed bit in its header that was, by spec, always set to 1. Predictably, boxes started using “that bit is always 1” as a way to detect and mess with QUIC. So the IETF published RFC 9287, “Greasing the QUIC Bit,” which lets endpoints agree to randomize it — greasing the one bit that was supposed to be constant, for the exact same reason. HTTP/2 implementations send unknown settings and frames that peers must ignore. The reserved-value-you-send-on-purpose has gone from a hack in Chrome’s TLS code to a standard defensive move across the whole stack.
There’s even a twist that turns GREASE into a security-tool footnote. TLS fingerprinting — JA3, and its successor JA4 — identifies a client by hashing the exact list of cipher suites and extensions it offers. GREASE broke the naive version of that, because if the values are random per connection, every Chrome handshake hashes to something different and the fingerprint is useless. Fingerprinters had to learn to strip the 0x?A?A values out before hashing. Then Chrome went a step further and started randomizing the order of its extensions too, in 2023 — because servers had begun ossifying around the fixed order, treating “extensions in exactly this sequence” as a signature of a real browser. Same disease, same treatment: if a thing can be depended on, and depending on it would freeze the protocol, then make the thing vary so nobody can depend on it.
That’s the quiet lesson under all of it. A spec that says “you MUST ignore unknown values” is just words; it does nothing on its own, because nothing makes anyone obey it until it’s too late to matter. What actually keeps a protocol extensible isn’t the clause in the RFC — it’s traffic that constantly puts the clause to the test. The internet’s ability to evolve turned out to depend on a browser shipping deliberate garbage, forever, so the doors it might need someday never rust shut. 0x0A0A means nothing. That’s the entire point.