CVE-2026-82208: Verified Reproduction
CVE-2026-82208: curl: wolfSSL CA-cache hit causes x509 store setup rerun that overrides user certificate verification callback
CVE-2026-82208 is verified against curl/curl · github. Affected versions: curl 8.9.1 through 8.21.0 inclusive. This low reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00368.
What Is CVE-2026-82208?
CVE-2026-82208 is a low-severity vulnerability affecting curl/curl curl 8.9.1 through 8.21.0 inclusive.. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00368).
CVE-2026-82208 Severity
CVE-2026-82208 is rated low severity.
Low — limited impact or hard to exploit. Address in the normal cycle.
Affected curl/curl Versions
curl/curl · github versions curl 8.9.1 through 8.21.0 inclusive. are affected.
How to Reproduce CVE-2026-82208
pruva-verify REPRO-2026-00368 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00368/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-82208
- reached the target end-to-end
- full exploit chain demonstrated
- high confidence
- the upstream fix blocks the same trigger
An HTTPS peer certificate trusted by the cached CA store but rejected after the CURLOPT_SSL_CTX_FUNCTION callback replaces the trust store with an empty store
- curl_multi API
- first CAfile transfer populates wolfSSL CA cache
- fresh second transfer invokes CURLOPT_SSL_CTX_FUNCTION
- vulnerable Curl_wssl_setup_x509_store rerun reinstalls cached store
How the agent worked
Root Cause and Exploit Chain for CVE-2026-82208
CVE-2026-82208 is a certificate-policy bypass in libcurl's wolfSSL TLS backend. When CA caching is enabled, a cache-hit connection can leave wssl->x509_store_setup false. libcurl calls Curl_wssl_setup_x509_store() before an application's CURLOPT_SSL_CTX_FUNCTION callback, the callback replaces the trust store with stricter application policy, and then libcurl calls setup again during the handshake. The vulnerable second call silently reinstalls the cached CA store, overriding the callback's policy. Current-run testing reproduced the bypass twice against the vulnerable fixed-commit parent and showed the fixed commit rejecting the same second transfer twice.
- Package/component affected: curl/libcurl, specifically the wolfSSL TLS backend when CA caching and
CURLOPT_SSL_CTX_FUNCTIONtrust-store customization are used. - Affected versions: curl 8.9.1 through 8.21.0 inclusive. Versions before 8.9.1 and curl 8.22.0 or later are not affected.
- Tested vulnerable commit:
f8df560ed9faa2ff3d6198b50f55eaf0315fcb39, the direct parent of the fixed commit. - Tested fixed commit:
ed0338befd1d865a8ea1fbaa90013a096dedd07a. - Risk level and consequences: Upstream rates this Low severity (CWE-295). Under the required application configuration, an HTTPS peer certificate accepted by the cached CA store can be accepted even though application-installed certificate policy rejects it, undermining authentication and authorization decisions based on that policy. The curl command-line tool is not affected because this requires libcurl callback use.
Impact Parity
- Disclosed/claimed maximum impact: Certificate-policy/authorization bypass (
authz_bypass). - Reproduced impact from this run: Full policy bypass. On each vulnerable run, the application callback installed an empty wolfSSL trust store, yet the second TLS handshake succeeded and received HTTP 200 from the peer. The fixed commit failed the same transfer with
CURLE_SSL_CACERT_BADFILE(77) after reporting that the CA signer was unavailable. - Parity:
full. - Not demonstrated: No code execution, memory corruption, or effect beyond bypassing the configured certificate trust policy was claimed or tested.
Root Cause
The CA cache is held on the libcurl multi handle. In the vulnerable implementation, the line that marks setup complete—wssl->x509_store_setup = TRUE—is inside wssl_populate_x509_store(). A cache miss populates a new store and reaches that assignment. A cache hit, however, takes the cached_store branch in Curl_wssl_setup_x509_store() and returns without calling wssl_populate_x509_store(), so the completion flag remains false.
During a new wolfSSL connection, libcurl first checks this flag and installs the cached store before calling the application's CURLOPT_SSL_CTX_FUNCTION callback. The callback can replace the trust store to enforce stricter policy. Later in the handshake, libcurl checks the still-false flag again, invokes Curl_wssl_setup_x509_store() a second time, and restores the cached store. The callback did execute, but its trust decision state no longer controls certificate validation.
The fix moves wssl->x509_store_setup = TRUE to the beginning of Curl_wssl_setup_x509_store(), ensuring every path—including a cache hit—is marked complete and preventing the post-callback rerun:
- Fix: https://github.com/curl/curl/commit/ed0338befd1d865a8ea1fbaa90013a096dedd07a
- Introduced by the CA-cache/UAF correction: https://github.com/curl/curl/commit/0f2876b2c33f6784a27b6f7345bd8cd95b46352a
Reproduction Steps
- Run
bundle/repro/reproduction_steps.shwithPRUVA_ROOToptionally pointing to the bundle directory. - The script reads
bundle/project_cache_context.json, uses/pruva/project-cache/repowhen prepared, fetches fixed commited0338befd1d865a8ea1fbaa90013a096dedd07a, resolves its parent as the vulnerable checkout, and verifies the patch is absent/present in the expected function preamble. - It builds pinned wolfSSL 5.8.4 commit
59f4fa568615396fbf381b073b220d1e8d61e4c2and static vulnerable/fixed libcurl builds with no default CA path. This makes the explicit CAfile the sole trust source and satisfies the wolfSSL CA-cache criteria. - It generates a local CA/server certificate and starts a real local HTTPS peer.
- For each role, a C application performs one CAfile-authenticated transfer to populate the multi handle's CA cache, then a fresh second transfer with
CURLOPT_SSL_CTX_FUNCTION. The callback replaces the wolfSSL X.509 store with an empty store, which must reject the server certificate if preserved. - The script runs two vulnerable and two fixed attempts. It requires vulnerable HTTP 200 acceptance, fixed certificate rejection, and exactly six HTTP requests reaching the peer (four vulnerable requests plus two fixed cache-priming requests).
- It writes
bundle/repro/runtime_manifest.jsonwith immutable target identity and proof-artifact SHA-256 values.
Expected terminal output is:
CVE-2026-82208 CONFIRMED: vulnerable CA-cache hit overrides callback-selected trust store; fixed commit fails closed.
Evidence
- Vulnerable attempts:
bundle/repro/vulnerable-attempt-1.logbundle/repro/vulnerable-attempt-2.log
- Fixed negative controls:
bundle/repro/fixed-attempt-1.logbundle/repro/fixed-attempt-2.log
- Real HTTPS peer transcript:
bundle/repro/https-peer.log - Exact source/dependency identity:
bundle/repro/target-identity.log - Machine-readable evidence binding:
bundle/repro/runtime_manifest.json - Build/session diagnostics:
bundle/logs/reproduction_steps.logandbundle/logs/fix.patch
Key vulnerable excerpt (present in both vulnerable logs):
CALLBACK_EMPTY_STORE_INSTALLED
* SSL connection using TLSv1.3 / TLS13-AES256-GCM-SHA384
< HTTP/1.1 200 OK
SECOND_RESULT code=0 name=No error http=200
VULNERABILITY_CONFIRMED cached_CA_overrode_callback_policy
Key fixed excerpt (present in both fixed logs):
CALLBACK_EMPTY_STORE_INSTALLED
* CA signer not available for verification
SECOND_RESULT code=77 name=Problem with the SSL CA cert (path? access rights?) http=0
FIXED_NEGATIVE_CONTROL callback_policy_enforced
The final runtime manifest binds the tested vulnerable identity to SHA-256 ebf927ca04aa4ea5794dbdcc4f97ce45f184a311d935b1fbf5e6195d4a1b9252, computed from git:https://github.com/curl/curl.git@f8df560ed9faa2ff3d6198b50f55eaf0315fcb39. The observed environment was Linux x86-64, libcurl multi API, wolfSSL 5.8.4, and Python 3's TLS-capable local HTTPS peer. No sanitizer was used.
Recommendations / Next Steps
- Upgrade to curl 8.22.0 or later.
- If immediate upgrade is unavailable, apply upstream commit
ed0338befd1d865a8ea1fbaa90013a096dedd07aand rebuild libcurl. - As a temporary mitigation, avoid combining the wolfSSL backend, CA caching, and
CURLOPT_SSL_CTX_FUNCTIONtrust-store replacement. - Retain a regression test that primes a CAfile-only multi-handle cache, installs a callback-selected rejecting store on a fresh transfer, and confirms the policy remains effective on the cache-hit path.
- Test cache-hit and cache-miss branches independently; cache misses already set the old completion flag and therefore do not expose the same sequence.
Additional Notes
- The finalized script passed twice consecutively, and each script execution itself ran two vulnerable and two fixed attempts.
- The callback uses an empty trust store as a deterministic stricter policy. This models the advisory's callback-selected trust store and proves policy state is overridden without relying on application-specific certificate contents.
- The local HTTPS peer intentionally closes each HTTP connection. CA caching is independent of connection reuse; forcing a fresh TLS connection ensures the second connection reaches the vulnerable cache-hit setup sequence.
- A compiled-in default CA path initially prevented the cache criteria from being satisfied. The final build explicitly uses
--without-ca-bundle --without-ca-path, and the runtime logs confirmCApath: none.
CVE-2026-82208 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Artifacts and Evidence for CVE-2026-82208
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-82208
FAQ: CVE-2026-82208
Is CVE-2026-82208 exploitable?
How severe is CVE-2026-82208?
What type of vulnerability is CVE-2026-82208?
Which versions of curl/curl are affected by CVE-2026-82208?
How can I reproduce CVE-2026-82208?
Is the CVE-2026-82208 reproduction verified?
References for CVE-2026-82208
Authoritative sources for CVE-2026-82208 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.