HexBrain

curl · Report #4123646

TLS session cache key omits native_ca_store: a session validated with CURLSSLOPT_NATIVE_CA can be resumed by a transfer that disabled it (incomplete f

Informativestatus
lowseverity
6upvotes
20 Oct 2026disclosed

How it was found

Summary

CVE-2026-11564 fixed the connection pool so that a connection whose certificate was validated with the native CA store is not reused by a later transfer that switched to custom CA material. That same field, native_ca_store, is compared for connection reuse but is NOT part of the TLS session cache key. So a TLS session established and validated with CURLSSLOPT_NATIVE_CA can be resumed, on a brand-new connection, by a transfer that has native CA turned off. Resumption sends no server Certificate, so the second transfer never validates the peer and ends up trusting a server its own CA configuration would have rejected. Same certificate-validation bypass as CVE-2026-11564, reached through the session cache instead of the connection pool — i.e. that fix is incomplete.

Exact source lines:

  • native_ca_store IS required to match for connection reuse: lib/vtls/vtls_config.c:148 (c1->native_ca_store == c2->native_ca_store) &&

  • native_ca_store is NEVER added to the session cache key. ssl_peer_key_build() in lib/vtls/vtls_scache.c builds it; the verifypeer block (around lib/vtls/vtls_scache.c:292-317) adds CAfile, CApath, Issuer, CAInfoBlob, issuercert_blob — but not native_ca_store. Verify: git grep -n native_ca_store lib/vtls/vtls_scache.c returns 0 hits.

  • CURLSSLOPT_NATIVE_CA only flips the flag (lib/vtls/vtls_config.c:254); it does not change CAfile/CApath, so two configs differing only in native_ca_store build a byte-identical session key.

Affected version

master @ 8e3722b7 (8.23.1-DEV). Any build where CURLSSLOPT_NATIVE_CA is meaningful (OpenSSL with the native store loaded, Schannel, Secure Transport).

Steps To Reproduce

Preconditions: two transfers to the same https origin that share a TLS session cache (two easy handles sharing a CURLSHOPT_SSL_SESSION share, or two transfers on one multi handle), TLS resumption enabled (default), and a server whose certificate chains to a root present in the OS native store but NOT in the file bundle (realistic with an enterprise/MDM OS root).

  1. Handle A -> https://target, CURLSSLOPT_NATIVE_CA set, verifypeer on, default/empty CAfile. A validates the server cert against the native store and stores the TLS session (Curl_ssl_scache_put).
  2. Handle B -> same https://target, CURLSSLOPT_NATIVE_CA NOT set, same CAfile, verifypeer on. B builds the same session key, opens a new connection, and Curl_ssl_scache_get_session returns A's cached session. TLS resumes; no certificate is sent or validated.
  3. Result: B completes the handshake and trusts a server whose certificate its own (bundle-only) configuration would have rejected.

Negative control: give A and B the same native_ca_store value -> no bypass (intended behaviour). The bug is only the config mismatch being invisible to the session key.

The attached verify.sh proves the code-level asymmetry against a fresh clone (native_ca_store required for connection reuse, 0 occurrences in the session-key builder).

Suggested fix

Add native_ca_store to the verifypeer part of the session key in ssl_peer_key_build() (lib/vtls/vtls_scache.c), exactly as it is compared in match_ssl_primary_config() (lib/vtls/vtls_config.c:148). The ECH fields (ech/ech_config/ech_public) are also compared for reuse but absent from the key — worth adding in the same change.

Impact

Summary

A transfer that deliberately restricts trust to a file CA bundle can resume a TLS session that was only ever validated against the operating-system native CA store, and therefore accept a server certificate it would otherwise reject.

An active network attacker who holds a certificate trusted by one store but not the other (for example a cert chaining to a corporate/MDM root present in the OS store but absent from the application's bundle) can MITM the stricter transfer: it resumes the session and never re-validates the peer.

This is the same impact as CVE-2026-11564 (certificate validation bypass, CWE-295), reached through TLS session resumption rather than connection pooling, so the fix for that CVE is incomplete.

Not a bypass when: native CA is not used, the two configs use the same native_ca_store value, or no session cache is shared across differing configs. Hence Low severity, matching the parent CVE.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original