curl · Report #3973090
CVE-2026-82208: wolfSSL CA-cache hit overrides callback
How it was found
Summary
With the wolfSSL backend, when CA caching is enabled and an CURLOPT_SSL_CTX_FUNCTION callback replaces the trust store, curl can silently reinstall the cached store after the callback returns. A certificate trusted by the cached store but rejected by the callback-selected store is then incorrectly accepted.
Root cause
Curl_wssl_setup_x509_store() in lib/vtls/wolfssl.c installs a cached X509 store but does not set wssl->x509_store_setup = TRUE. That flag is only set inside wssl_populate_x509_store(), which runs on cache misses.
The sequence on a cache hit:
- Before invoking the callback,
wssl_connect_step1()callsCurl_wssl_setup_x509_store()— cached store A is installed, flag staysfalse. - The
CURLOPT_SSL_CTX_FUNCTIONcallback runs and replaces store A with store B. - During the handshake, the still-false flag causes
Curl_wssl_setup_x509_store()to run again. It findsCTX_get_cert_store() != cached_store(the callback changed it), so it reinstalls cached store A.
Affected versions
Introduced in commit 0f2876b2c33f (Jul 2024, "wolfSSL: CA store share fix" for #14278). Present in releases 8.9.1 through 8.21.0.
Impact
An application that uses CURLOPT_SSL_CTX_FUNCTION to restrict trust (e.g. pin to a private CA) has that restriction silently bypassed when CA caching is active. A MITM presenting a certificate valid under the cached store but rejected by the callback's store succeeds.
Prerequisites: wolfSSL backend, CURLOPT_CA_CACHE_TIMEOUT != 0, a callback that replaces the store, and differing trust between the two stores.
Reproduction
- Build an affected curl release (8.9.1 through 8.21.0) against wolfSSL and configure curl without a compiled-in default CA path so that a CA file is eligible for caching.
- Create two independent certificate authorities, called CA A and CA B.
- Create a TLS server certificate for the test hostname, including a matching subject alternative name, and sign it with CA A.
- Start an HTTPS server on the test hostname using that certificate.
- Write a small libcurl client that uses the same multi handle for two transfers, sets
CURLOPT_CAINFOto CA A, and sets a nonzeroCURLOPT_CA_CACHE_TIMEOUT. - Make the first transfer without an SSL-context callback. Confirm that it succeeds and thereby populates curl's CA cache with the trust store containing CA A.
- For the second transfer, use a fresh connection and register
CURLOPT_SSL_CTX_FUNCTION. In the callback, replace the wolfSSL context's certificate store with a newly created store containing only CA B. - Disable connection reuse and TLS session caching for both transfers so that the second transfer performs a new TLS handshake and certificate verification.
- Make the second transfer to the same HTTPS server. On a vulnerable build, it incorrectly succeeds even though the callback-selected store contains only CA B and the server certificate chains only to CA A.
- Repeat the sequence with
CURLOPT_CA_CACHE_TIMEOUTset to zero. The second transfer should now fail certificate verification, demonstrating that the unexpected acceptance depends on the CA-cache path. - As a fixed-version check, repeat the cached sequence on a build containing commit
ed0338befdor a later release. The second transfer should fail because curl no longer reinstalls CA A after the callback selects CA B.
The callback-selected trust store must remain authoritative. The transfer using store B should reject the server certificate regardless of whether curl's CA cache was previously populated.
Suggested fix
Set wssl->x509_store_setup = TRUE in Curl_wssl_setup_x509_store() itself (before returning), rather than only inside wssl_populate_x509_store(). This ensures the flag is set on both cache hits and misses, preventing the second invocation from overwriting the callback's store.
Impact
Summary:
An attacker able to present a hostname-valid certificate trusted by curl’s cached CA store—but rejected by the application-selected store—can impersonate the intended TLS endpoint. This bypasses the application’s trust policy and may allow interception or modification of encrypted traffic.