Closed Bug 2026946 Opened 7 months ago Closed 7 months ago

Use-after-free in tls13_HandleCertificateRequest via repeated post-handshake CertReq

Categories

(NSS :: Libraries, defect)

defect

Tracking

(Not tracked)

RESOLVED DUPLICATE of bug 2026089

People

(Reporter: social, Assigned: djackson)

Details

(4 keywords, Whiteboard: [client-bounty-form])

Attachments

(1 file, 1 obsolete file)

18.20 KB, application/gzip
Details

A malicious TLS 1.3 server can crash any NSS client — including Firefox — by sending repeated post-handshake CertificateRequest messages. The attack takes 2.9 KB on the wire and under 100 ms. No MITM, no credentials, no special positioning. Embedded in an ad network or CDN endpoint, this would hit every connecting Firefox or PKCS#11 client. The bug has been present since NSS 3.43 (March 2019).

Reproduction

tstclnt crash (requires libnss3-tools, python3-cryptography):

python3 poc_nss_certreq_memleak_standalone.py

Firefox crash (requires firefox-esr):

python3 poc_nss_certreq_firefox.py --headless

Firefox crashes with SIGSEGV in milliseconds. Post-handshake authentication is configured automatically by the PoC; no client cert or PKCS#11 module required. Full report in attached ADVISORY.md.

What happens

The PoC completes a real TLS 1.3 handshake (X25519 + ECDSA-P256), then sends repeated encrypted CertificateRequest messages. Each one leaks a PK11 hash context (~200-300 bytes) by overwriting ss->ssl3.hs.shaPostHandshake without freeing the previous value. After 73 re-entries, heap metadata corruption causes xtnData->sigSchemes to point into a previously freed SQLite cert DB buffer. PORT_Free receives a stale, misaligned pointer (0x5555555f000d), crashing the process.

This is heap corruption, not resource exhaustion. On allocators without pointer validation (embedded systems, older libraries), this corruption pattern could potentially be leveraged beyond a crash.

Root cause

tls13_HandleCertificateRequest() in lib/ssl/tls13con.c clones a transcript hash context (PK11_CloneContext at line 3138) on each post-handshake CertificateRequest but never frees the previous clone. The cleanup block (lines 3149-3168) handles five other fields — clientCertChain, clientCertificate, clientPrivateKey, clientAuthSignatureSchemes, certReqContext — but omits shaPostHandshake. PORT_Assert(shaPostHandshake == NULL) at line 3137 confirms the developers intended this to be NULL on re-entry. The assert fires on the second CertReq in debug builds but is compiled out in release.

Fix: free the previous shaPostHandshake before cloning. Design options in ADVISORY.md.

Affected

NSS 3.43 through 3.110 (current). Any NSS consumer with SSL_ENABLE_POST_HANDSHAKE_AUTH: PKCS#11/HSM middleware, smartcard clients, enterprise Firefox with security.tls.enable_post_handshake_auth. CWE-416 (Use After Free). CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H = 7.5 (High).

URL: (not applicable — NSS library vulnerability, not a web page)

Attachment: VULN-NSS-POSTHANDSHAKE-CERTREQ-HEAPCORRUPT.tar.gz (contains ADVISORY.md, poc_nss_certreq_memleak_standalone.py, poc_nss_certreq_firefox.py)

Flags: sec-bounty?
Assignee: nobody → nobody
Group: firefox-core-security → crypto-core-security
Component: Security → Libraries
Product: Firefox → NSS
Attached file (secure) (obsolete) —
Severity: -- → S3
Status: UNCONFIRMED → NEW
Ever confirmed: true

[Comment made in error, deleted]

Thank you for the detailed report and the reproduction scripts. This issue was reported to us 2 days before your report in bug 2026089.

The crash you're reporting is a real bug, however, the root cause analysis is incorrect and I don't think ss->ssl3.hs.shaPostHandshake is involved.

Regarding the shaPostHandshake analysis: PHA exchanges are serialized by the
restartTarget guard in ssl3_GatherCompleteHandshake (ssl3gthr.c:482-486). While a PHA
response is pending -- whether synchronously in-flight or waiting for the async
SSL_ClientCertCallbackComplete callback -- the gather loop returns PR_WOULD_BLOCK_ERROR
without processing further records. A second CertificateRequest cannot reach
tls13_HandleCertificateRequest until the first PHA completes, at which point
tls13_SendPostHandshakeCertificate (tls13con.c:3244-3245) has already destroyed and NULLed
shaPostHandshake. The PORT_Assert(shaPostHandshake == NULL) is always valid, and the leak
described in the report is not reachable.

Please let me know if you disagree with this analysis.

Assignee: nobody → djackson
Status: NEW → RESOLVED
Closed: 7 months ago
Duplicate of bug: CVE-2026-6772
Resolution: --- → DUPLICATE
Attachment #9559271 - Attachment is obsolete: true
Flags: sec-bounty? → sec-bounty-
Group: crypto-core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: