BAD SKY.NET

pre_shared_key

pre_shared_key offers a key from an earlier session for fast TLS 1.3 resumption. It is always the last extension.

TLS extensionCode 0x0029 (41)

What it is

pre_shared_key (extension 41) is defined in RFC 8446. When a client resumes a TLS 1.3 session, it sends the identity of a pre-shared key it received earlier, usually from a session ticket, together with a binder value that proves it holds the key.

RFC 8446 requires pre_shared_key to be the last extension in the ClientHello, because the binder is computed over everything before it. It is the only extension with a fixed position, even in browsers that otherwise shuffle their extensions.

Combined with psk_dhe_ke from psk_key_exchange_modes, resumption still runs a fresh key exchange, so forward secrecy is kept. The same mechanism also carries 0-RTT early data when the client uses it.

If the server accepts the key, it answers with the index of the chosen identity, and the handshake skips the certificate exchange, which makes resumption faster.

Who sends it

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

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

Why it matters for fingerprinting

Only our Chrome capture contains it, as the last of its 17 named extensions. That capture was a resumption attempt, while all the library measurements were fresh connections with nothing to resume, so their missing pre_shared_key is not a library trait. It does mean the same client can show two extension counts, and two JA4 values, depending on whether it resumed.

Check whether your client sends it

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

Run the TLS fingerprint test

References

Related