CVE-2026-10536: Verified Reproduction
CVE-2026-10536: libcurl HTTP/2 stream-dependency tree use-after-free
CVE-2026-10536 is verified against curl/libcurl · github. Affected versions: 7.88.0 to 8.20.0 inclusive. Fixed in curl 8.21.0. Vulnerability class: Use-After-Free. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00278.
What Is CVE-2026-10536?
CVE-2026-10536 is a high-severity heap use-after-free (CWE-416) in libcurl's HTTP/2 stream-dependency bookkeeping. An application that uses the deprecated stream-dependency options can make libcurl dereference an already-freed dependency-tree node. Pruva reproduced it (reproduction REPRO-2026-00278).
CVE-2026-10536 Severity & CVSS Score
CVE-2026-10536 is rated critical severity, with a CVSS base score of 9.8 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected curl/libcurl Versions
curl/libcurl · github versions 7.88.0 to 8.20.0 inclusive are affected.
How to Reproduce CVE-2026-10536
pruva-verify REPRO-2026-00278 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00278/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-10536
- reached the target end-to-end
- crash observed
- high confidence
CURLOPT_STREAM_DEPENDS set on an easy handle, followed by curl_easy_reset and curl_easy_cleanup order
- curl_easy_setopt(CURLOPT_STREAM_DEPENDS)
- curl_easy_reset(child)
- curl_easy_cleanup(child)
- curl_easy_cleanup(parent)
How the agent worked
Root Cause and Exploit Chain for CVE-2026-10536
CVE-2026-10536 is a heap use-after-free (UAF) in libcurl's HTTP/2 stream-dependency bookkeeping. When an application sets CURLOPT_STREAM_DEPENDS (or CURLOPT_STREAM_DEPENDS_E) on an easy handle, then calls curl_easy_reset() on that handle and later curl_easy_cleanup() on both handles, libcurl can dereference a dependency-tree node that was already freed. The vulnerability requires HTTP/2 support (nghttp2) and use of the now-deprecated dependency options. It is reachable through the public libcurl API (curl_easy_setopt, curl_easy_reset, curl_easy_cleanup) without any network traffic.
- Package/component affected: curl / libcurl, HTTP/2 stream priority/dependency code (
lib/url.c,priority_remove_child,data_priority_cleanup). - Affected versions: curl 7.88.0 through 8.20.0 inclusive (per upstream advisory); introduced by commit
71b7e0161032927cdfband fixed by commitbfbff7852f050232edd3e5ca5c6bf2021c340f5a. - Risk level and consequences: High / memory corruption. The UAF occurs during easy-handle cleanup, so a controlled memory layout could potentially lead to further memory corruption. The upstream advisory classifies the issue as a use-after-free with CVSS severity Low, but the demonstrated impact is a real memory-safety violation in a widely used library. It does not affect the curl command-line tool directly; only applications that programmatically use the deprecated dependency options are exposed.
Impact Parity
- Disclosed/claimed maximum impact: memory corruption (use-after-free).
- Reproduced impact from this run: A deterministic AddressSanitizer
heap-use-after-freereport inpriority_remove_childatlib/url.c:3516when the parent handle is cleaned up after the child handle has been reset and freed. - Parity:
fullfor the memory-safety claim. The reproduction proves the exact vulnerability class (UAF) and the exact API surface described in the advisory. - Not demonstrated: No remote code execution or full exploit chain was demonstrated; only the UAF crash/reachability is proven, which is sufficient for the claimed memory-corruption impact.
Root Cause
The bug is in the priority-child doubly-linked bookkeeping in lib/url.c:
curl_easy_setopt(child, CURLOPT_STREAM_DEPENDS, parent)adds aCurl_data_prio_nodetoparent->set.priority.children; that node stores a raw pointer tochild. It also setschild->set.priority.parent = parent.curl_easy_reset(child)executesmemset(&data->set, 0, sizeof(struct UserDefined)), which zeroschild->set.priorityand therefore clearschild->set.priority.parent. The child handle now "forgets" that it is a dependent ofparent, butparent->set.priority.childrenstill contains the node pointing atchild.curl_easy_cleanup(child)callsdata_priority_cleanup(child). Becausechild->set.priority.parentis now zero, the code does not remove the child node from its parent list. TheCurl_easystruct forchildis then freed.curl_easy_cleanup(parent)callsdata_priority_cleanup(parent), which loops overparent->set.priority.children. The first node still points to the freedchildstruct, sopriority_remove_child(parent, child)readschild->set.priority.parent(offset 2120 inside the freedCurl_easy) and crashes under AddressSanitizer.
- Fix commit: https://github.com/curl/curl/commit/bfbff7852f050232edd3e5ca5c6bf2021c340f5a ("http2: remove stream dependency tracking"). The upstream fix removes the entire HTTP/2 stream-dependency feature, making
CURLOPT_STREAM_DEPENDSandCURLOPT_STREAM_DEPENDS_Eno-ops, which eliminates the faulty bookkeeping.
Reproduction Steps
- Run
bundle/repro/reproduction_steps.sh. It is self-contained: it installs build dependencies, clones or reuses the curl repository, builds two static ASan-enabled libcurl installations (vulnerablecurl-8_20_0and fixedbfbff7852f), compiles a small C reproducer, and runs it against both. - The reproducer creates two easy handles, sets
CURLOPT_STREAM_DEPENDSon the child so it depends on the parent, callscurl_easy_reset(child)andcurl_easy_cleanup(child), then callscurl_easy_cleanup(parent). - Expected evidence:
- Vulnerable build: AddressSanitizer reports
heap-use-after-freeinpriority_remove_child(lib/url.c:3516). - Fixed build: reproducer exits cleanly with no sanitizer report.
- Vulnerable build: AddressSanitizer reports
Evidence
bundle/logs/reproduction_steps.log— full script output.bundle/logs/reproducer_vuln.log— ASan heap-use-after-free report for the vulnerable build.bundle/logs/reproducer_fixed.log— clean run for the fixed build.bundle/repro/reproducer.c— source of the minimal C harness.bundle/repro/runtime_manifest.json— structured runtime evidence manifest.
Key excerpt from the vulnerable run:
==ERROR: AddressSanitizer: heap-use-after-free on address ... at pc ... in priority_remove_child lib/url.c:3516
READ of size 8 at ... thread T0
#0 priority_remove_child /.../lib/url.c:3516
#1 data_priority_cleanup /.../lib/url.c:3588
#2 Curl_close /.../lib/url.c:280
#3 curl_easy_cleanup /.../lib/easy.c:844
The freed region was the Curl_easy struct allocated in Curl_open during curl_easy_init, and it was freed by curl_easy_cleanup(child) before curl_easy_cleanup(parent) accessed it through the stale dependency node.
Recommendations / Next Steps
- Upgrade: Upgrade libcurl to 8.21.0 or later, where the dependency feature has been removed and the option is a no-op.
- Workaround: Applications that currently use
CURLOPT_STREAM_DEPENDSorCURLOPT_STREAM_DEPENDS_Eshould stop using these deprecated options; they are no longer functional in 8.21.0+. - Testing: For any cherry-picked patch, verify that
curl_easy_setopt(..., CURLOPT_STREAM_DEPENDS, ...)followed bycurl_easy_resetandcurl_easy_cleanupno longer produces a use-after-free under ASan/Valgrind.
Additional Notes
- Idempotency: The reproduction script was run twice consecutively and produced the same confirmed result both times. Cached builds in the project cache are reused when the recorded commit matches, making subsequent runs fast.
- Limitations: The proof is a library/API harness that directly calls the affected libcurl functions. It does not exercise a remote network path because the advisory describes an application-level API misuse, not a network-triggered vulnerability.
CVE-2026-10536 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-10536
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-10536
Upgrade curl/libcurl · github to curl 8.21.0 or later.
FAQ: CVE-2026-10536
What conditions are required to trigger CVE-2026-10536?
Which versions of libcurl are affected by CVE-2026-10536, and where is it fixed?
How can I reproduce CVE-2026-10536?
References for CVE-2026-10536
Authoritative sources for CVE-2026-10536 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.