Fixing HTTP/2 Use-After-Free CVE-2026-92392 in curl 8.23.0
Contents
TL;DR
What happened curl and libcurl versions 8.12.0 through 8.22.0 contain a High-severity Use-After-Free vulnerability (CVE-2026-92392) during HTTP/2 uploads. When an untrusted server abruptly resets an upload stream, libcurl can retain a dangling pointer that leads to heap corruption and potential client-side remote code execution (RCE).
What to do Upgrade to curl 8.23.0 or install the security backports provided by your Linux distribution.
Workaround Avoid HTTP/2 for uploads to untrusted servers, or force HTTP/1.1 using the --http1.1 flag.
On October 14, 2026, the curl project released version 8.23.0.
The team accelerated its usual eight-week release cycle by two weeks specifically to address CVE-2026-92392, a serious flaw in its HTTP/2 upload implementation.
This issue affects both the standalone curl command-line utility and libcurl, the shared library embedded across countless runtimes and network clients.
The curl project maintains its own four-tier severity scale (Low, Medium, High, and Critical), and CVE-2026-92392 received a High rating.
This is only the third High-severity advisory issued by the project since 2021.
Rather than remaining a pure denial-of-service (DoS) bug, proof-of-concept testing proved that a rogue server could exploit the flaw to execute arbitrary code on the client under specific memory conditions.
Dangling Pointers and Heap Overwriting in RST_STREAM Handling
The root cause stems from a mismatch between HTTP/2 multiplexing—processing multiple concurrent streams within a single connection—and how curl manages internal transfer lifecycles.
In libcurl, each active transfer is tracked via an easy handle (struct Curl_easy), while an overarching multi handle drives these parallel streams.
The vulnerability triggers when a client uploads data to an adversarial server over HTTP/2.
The server halts data ingestion by setting the stream window size to zero, returns partial response headers, and abruptly sends an RST_STREAM frame with error codes like HTTP_1_1_REQUIRED or REFUSED_STREAM.
Receiving this frame terminates the logical transfer stream, while the underlying physical TCP connection stays alive.
During this transition, curl marks the transfer as complete but fails to clear its internal pointer referencing the corresponding easy handle.
When the caller application detects the stream termination, it frees the easy handle.
If subsequent multi handle operations proceed, libcurl misinterprets its internal transfer state and allocates memory for downloading. Because dynamic memory allocators prioritize recently freed chunks, the newly requested memory occupies the exact heap location of the discarded easy handle, and directly writes inbound server data into freed memory.
ASLR Bypasses and Function Pointer Hijacking Prerequisites
When this use-after-free condition triggers, the initial exploitation steps leak internal client memory addresses back to the server.
Even though modern operating systems enforce Address Space Layout Randomization (ASLR), this address leakage enables an attacker to calculate runtime memory offsets.
The server then supplies a crafted structure over the wire. Once libcurl invokes a hijacked function pointer inside the overwritten memory, execution transfers to an attacker-controlled address to achieve client-side remote code execution.
However, the proof-of-concept requirements are extremely strict.
The exploit requires the client to upload roughly 135 KB of data over a valid TLS session to an attacker-controlled server.
Furthermore, the attacker must have exact foreknowledge of the target curl binary build flags, system architecture, and libc heap allocation behaviors (such as glibc arena mechanics). OpenSSL TLS 1.3 session ticket buffers and nghttp2 internal allocations must align exactly. The payload size capable of executing commands is also limited to around 23 bytes.
If any memory layout offset or network timing condition fails to align, the function pointer call triggers an invalid memory access and immediately terminates the client process.
Because broad or automated exploitation across diverse production environments is exceptionally difficult, the curl project classified the advisory as High rather than Critical.
Detection and Coordinated Disclosure by AI Scanners
Security researcher Luna Tong at Anthropic discovered and reported the vulnerability.
The flaw was identified using an advanced open-source vulnerability scanner powered by AI models, accompanied by a fully reproducible Docker testbed and working proof of concept.
Earlier this year, we analyzed fictitious CVEs manufactured against SQLite by hallucinating LLMs, where unverified vulnerability reports referencing nonexistent source lines flooded vulnerability registries.
In contrast, this discovery demonstrated an AI-assisted analysis tool correctly tracing intricate protocol state transitions and memory lifecycle flaws that human audits frequently miss.
curl founder Daniel Stenberg commended the quality and precision of the reproduction materials in an official project write-up.
Memory Safety in C and the Decision Against Rust Rewrites
Regarding CWE-416 (Use-After-Free), Stenberg candidly acknowledged that choosing C is what allowed this class of bug to exist in the first place.
In languages where pointer lifetimes depend entirely on developer diligence, preventing subtle edge-case omissions across asynchronous, high-concurrency protocols like HTTP/2 remains difficult.
At the same time, Stenberg explicitly rejected rewriting curl in memory-safe languages such as Rust.
Over nearly thirty years, curl has been ported and tuned across hundreds of operating systems and dozens of CPU architectures.
No alternative language currently matches this level of platform ubiquity. Porting the codebase would stall active development and introduce new implementation regressions.
Instead, the project continues internal refactoring efforts, such as replacing raw struct pointers with transient Transfer IDs looked up on demand.
Affected Versions and Remediation
CVE-2026-92392 impacts curl and libcurl versions 8.12.0 through 8.22.0.
Releases prior to 8.12.0 and the newly published 8.23.0 release are unaffected.
Maintained long-term support branches have received corresponding patch releases, including 8.20.2, 8.16.2, and 8.14.3.
The recommended fix is upgrading to curl 8.23.0 or installing security backports from your Linux distribution.
In environments where an immediate upgrade is not feasible, restrict HTTP/2 on transfers to untrusted endpoints, or enforce HTTP/1.1 by passing --http1.1 to the command line or setting CURLOPT_HTTP_VERSION to CURL_HTTP_VERSION_1_1.