ML-KEM-768 key share: 1,184 bytes·ClientHello now spans two TCP packets·default in Chrome since 124, Firefox since 132·the fix is middlebox firmware, not a browser flag

What the browsers changed

TLS 1.3 lets client and server agree on a session key through a key exchange, and until recently that meant elliptic curves, usually X25519, with a 32-byte public key. The concern that made everyone move is not a quantum computer that exists, it is the recordings: encrypted traffic captured today can be decrypted retroactively once the key exchange falls, so long-lived secrets needed protection years in advance.

The answer that shipped is a hybrid. Chrome 124 turned it on by default in April 2024, first with the draft algorithm Kyber, then from Chrome 131 with the finished NIST standard under the name ML-KEM. Firefox followed in version 132. The browser sends two key shares in one hello, X25519 and ML-KEM-768, and the session key mixes both, so breaking the connection requires breaking both algorithms. Cryptographically it is a straightforward belt-and-suspenders design, and servers that don’t support ML-KEM simply pick the classical share.

Then the packets hit the real internet.

1,184 bytes that don’t fit

An ML-KEM-768 encapsulation key is 1,184 bytes. Add it to a ClientHello that historically weighed a few hundred bytes and the first message of a TLS connection no longer fits in a single TCP segment on a standard 1,500-byte MTU. It arrives as two packets.

Correct TCP code does not care, a stream is a stream. But a class of middleboxes, firewalls doing TLS inspection, intrusion prevention systems, some load balancers and out-of-date TLS libraries, had silently assumed the whole ClientHello shows up in the first read. Some parse what they got and reject it as malformed, some wait forever for bytes they already received, some drop the connection. David Adrian’s tldr.fail documents the failure class and its fixes, and its name is the diagnosis: too long, didn’t read.

Early rollout telemetry put the breakage at very roughly one connection in two thousand, concentrated in enterprise networks, which is simultaneously tiny and enormous: invisible in consumer traffic, and a support-ticket flood inside an affected company where every connection crosses the same appliance. Google’s rollout notes name the pattern politely as equipment that “does not correctly handle” large ClientHellos. The engineers involved spent months coordinating fixes with vendors, including Fortinet appliances, Zscaler paths and individual endpoints at large providers.

What the failure looks like from a desk

The symptoms are maddeningly nonspecific, which is why this bug gets misdiagnosed as flaky Wi-Fi or a broken site:

  • ERR_TIMED_OUT or ERR_CONNECTION_RESET in Chrome and Edge for some sites, on some networks, while other browsers on the same machine work, because they don’t send the hybrid share yet or sized it differently.
  • The same site loads fine on a phone hotspot, over a VPN, or from home.
  • curl from the same machine succeeds, since most curl builds negotiate without the post-quantum group.
  • Nothing in the server logs, because the connection died in the middle, before the server saw a complete hello.

The differential test is one command. A handshake forced through the hybrid group, openssl s_client -groups X25519MLKEM768, fails on the broken path and succeeds elsewhere, while the same command with -groups x25519 works on both. Two runs and you know it is the network path, not the site. Note the failure happens before certificates even enter the picture, which distinguishes it from the chain errors that produce loud, specific messages.

Kyber, Dilithium and the sci-fi shelf

A short intermission the topic has earned. The algorithm’s original name was CRYSTALS-Kyber, from the research suite “Cryptographic Suite for Algebraic Lattices”, and its companion signature scheme was CRYSTALS-Dilithium. Kyber crystals power lightsabers in Star Wars, dilithium crystals power warp drives in Star Trek. The cryptographers armed both franchises evenly, and NIST then standardized the pair under the considerably less fun names ML-KEM and ML-DSA.

Fix the box, keep the crypto

The tempting fix in an enterprise is the escape hatch: Chrome’s PostQuantumKeyAgreementEnabled policy turns the hybrid share off fleet-wide and makes the tickets stop today. It is the wrong place to stop. The policy is explicitly temporary and scheduled for removal, at which point the unpatched appliance breaks again, this time without an off switch, and every month on the classical-only path is a month of recordable traffic.

hides the bug until the policy is removed
// Chrome enterprise policy
{
  "PostQuantumKeyAgreementEnabled": false
}
// fleet-wide, and quantum-vulnerable
// key exchange for every connection
finds the hop that drops big hellos
openssl s_client \
  -groups X25519MLKEM768 \
  -connect internal-gw.example.com:443
# fails here, works from outside:
# that appliance needs its firmware update

The durable fix is inventory and firmware: find the inspection points in the path, check each vendor’s advisory for large-ClientHello handling, update, and only use the policy to bridge the weeks until the change window. Vendors have had fixes out since 2024, and tldr.fail keeps the list of known-affected implementations.

The wider lesson is about ossification. The internet had quietly hardened around the assumption that a hello fits in one packet, and it took a browser fleet the size of Chrome’s to break that assumption on purpose and make the ecosystem repair itself. The next size jump is already visible, because post-quantum signatures will eventually grow the certificate side too, and the machinery for replacing certificates fast is exactly what the shrinking certificate lifetimes are building. The handshake you debug this year is infrastructure maintenance for the next twenty.

Hybrid handshake questions

Why do TLS handshakes fail only on our corporate network?

Because the equipment in the middle is the variable. Browsers now send a post-quantum key share that pushes the ClientHello past one TCP packet, and some firewalls, TLS-inspection proxies and load balancers read only the first packet before judging the handshake. At home the same browser talks to the same site without that box in the path, and everything works. The fix is firmware on the middlebox, and vendors have been shipping it since 2024.

What is X25519MLKEM768?

The hybrid key exchange most browsers now use in TLS 1.3. X25519 and ML-KEM-768 run together, and an attacker would have to break both.

What does harvest now, decrypt later mean?

Recording encrypted traffic now to decrypt it once quantum computers can break the key exchange. Captured traffic stays sensitive for decades.

Can I turn off post-quantum key exchange in Chrome?

There is an enterprise policy for it, PostQuantumKeyAgreementEnabled, but it exists as a temporary escape hatch and Google has scheduled its removal. Treat it as a way to keep working this quarter while the actual middlebox gets patched, not as a fix.

Does post-quantum TLS make websites slower?

Barely, when everything in the path behaves. The key share adds about a kilobyte in each direction and ML-KEM itself computes fast. The measurable slowdowns come from broken paths: retries, fallbacks and middleboxes that stall on the larger hello.

Is my TLS certificate post-quantum now?

No. What browsers deployed is post-quantum key exchange. Certificates still carry RSA or ECDSA signatures, and migrating them is the next, slower chapter, since post-quantum signatures are much larger.

Which browsers send ML-KEM by default?

Chrome and Edge since version 124 in spring 2024, initially with Kyber and from Chrome 131 with the final ML-KEM standard, and Firefox since 132. Safari has been rolling it out across its platforms as well.

How do I test whether a server supports ML-KEM?

With a recent OpenSSL: openssl s_client -groups X25519MLKEM768 -connect host:443 either completes the handshake or fails immediately, which also makes it a handy probe for finding the network hop that eats large ClientHellos.