BAD SKY.NET

key_share

The TLS 1.3 extension that carries the client's public keys for the key exchange, so the handshake finishes in one round trip.

TLS extensionCode 0x0033 (51)

What it is

key_share (extension 51) is defined in RFC 8446 for TLS 1.3. The client sends one or more public keys, each for a group from its supported_groups list, for example X25519MLKEM768 and X25519. If the server supports one of those groups, it answers with its own share, and both sides derive the shared secret right away.

This is why a TLS 1.3 handshake needs only one round trip: the client guesses the group in advance. If it guesses wrong, the server replies with a HelloRetryRequest naming a group it accepts, and the client tries again, which costs an extra round trip.

The client normally sends shares for only one or two groups, because each share adds bytes to the ClientHello. Post-quantum hybrid shares are large: the X25519MLKEM768 share is over 1,200 bytes.

Who sends it

Chrome 153 (macOS) browser Sent at position 12
curl_cffi (impersonate chrome) Sent at position 15
curl-impersonate chrome116 Sent at position 13
curl-impersonate ff117 Sent at position 10
curl 8.7 (macOS) Sent at position 2
curl 7.88 (Debian 12) Sent at position 11
Python requests Sent at position 12
Python httpx Sent at position 12
Python httpx (HTTP/2) Sent at position 12
Go net/http Sent at position 11
Node.js fetch Sent at position 12
PHP Guzzle Sent at position 12

Measured on 2026-10-25 against our own test server: sent by 12 of 12 clients. Position counts from 1 and ignores GREASE values.

Why it matters for fingerprinting

Every measured client sends key_share, so its presence is not a signal. What differs is which groups get a share and the extension's position. The position varies widely: 2nd for macOS curl, 10th to 12th for most libraries, and random for Chrome, which shuffles its extensions on every connection.

Our test shows the supported groups list, not the individual shares, so the share choice is not part of the JA3 or JA4 values shown here.

Check whether your client sends it

Open the test from your browser, or call it from your script, and look for key_share in the TLS details.

Run the TLS fingerprint test

References

Related