{"id":3531,"date":"2026-10-14T14:05:34","date_gmt":"2026-10-14T14:05:34","guid":{"rendered":"https:\/\/thedigitalfortress.us\/?p=3531"},"modified":"2026-10-14T14:05:34","modified_gmt":"2026-10-14T14:05:34","slug":"curl-patches-http-2-upload-flaw-after-poc-demonstrates-client-side-code-execution","status":"publish","type":"post","link":"https:\/\/thedigitalfortress.us\/?p=3531","title":{"rendered":"curl Patches HTTP\/2 Upload Flaw After PoC Demonstrates Client-Side Code Execution"},"content":{"rendered":"<div id=\"articlebody\">\n<div class=\"separator\" style=\"clear: both;\"><a href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEj4S_5rQ2kApGYmSMOh6PFsgD3yRugV3_nzSexwBhEe3BoSTQeBfSu2-3JSO4wDCnU2LmVMWtgA6AcBEcf2wOpsL2v22woZ5fel0XaSonlbgDWSXMuV3iu5ewohp9kqgf4OwmCvtnRyyYjFEP6Z3RRLT5sX8g7-xI1robnLmWtqFp6SvrGvpBeXI_D4ICo\/s1700-nu-rw-lo-l85-e365\/curl.jpg\" style=\"display: block;  text-align: center; clear: left; float: left;\"><\/a><\/div>\n<p>A flaw in how curl handles HTTP\/2 uploads lets a malicious server receiving an upload corrupt the client&#8217;s memory, and the researcher who reported it turned that into code execution on the uploading machine.<\/p>\n<p>The curl project fixed it on October 14 in <a href=\"https:\/\/daniel.haxx.se\/blog\/2026\/10\/14\/curl-8-23-0\/\" target=\"_blank\">curl 8.23.0<\/a>. Taking over a client needs exact knowledge of its build and memory layout, and curl expects a real attack to end in a crash instead.<\/p>\n<p>The flaw, a use-after-free tracked as <a href=\"https:\/\/curl.se\/docs\/CVE-2026-92392.html\" target=\"_blank\">CVE-2026-92392<\/a>, affects curl and libcurl 8.12.0 through 8.22.0, both the command-line tool and the library that many other programs use for transfers. curl rates it High on its own four-level scale, its first High-severity flaw since the SOCKS5 heap overflow of October 2023. The project cut its release cycle by two weeks to ship the fix.<\/p>\n<p>The attack runs from the server side. The client has to upload a file of roughly 135KB over HTTP\/2 to a server controlled by the attacker, and the server&#8217;s certificate must pass the client&#8217;s checks. libcurl negotiates HTTP\/2 by default for https:\/\/ URLs when the server offers it, and the library was built with HTTP\/2 support.<\/p>\n<div class=\"dog_two clear\">\n<div class=\"cf\"><a href=\"https:\/\/thehackernews.uk\/growth-ai-control-d\" rel=\"nofollow noopener sponsored\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"lazyload\" alt=\"Cybersecurity\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjVYuoalvwUlwvLZFDideJ8jW4rz-IodX0Lwi7uyP7Ab0wiDeu_BqVhPDdejQQ65MC3p9Xc4MApnHz56NJ5SDc1HMg0DvozkkGYv9TGtDLCh26v1yD5-GyzQxnA5-6A6B4beW96H_6FyrByq22cvU5JDF-i8e5GIfV4wg1SpCvjwAJt74FaqkAb2gzqE7ll\/s728-nu-rw-lo-l85-e365\/core-d.png\" width=\"729\" height=\"91\"\/><\/a><\/div>\n<\/div>\n<p>The flaw has shipped in every curl release since 8.12.0 in February 2025. No source reports attacks that use it. The <a href=\"https:\/\/hackerone.com\/reports\/4030333\" target=\"_blank\">reporter&#8217;s HackerOne write-up<\/a>, with the malicious server script and a Docker container described as reproducing the code execution, became public on October 14 with the advisory.<\/p>\n<h3>What to Install, and What to Do Until Then<\/h3>\n<p><a name=\"more\"\/><\/p>\n<p>Upgrade to 8.23.0 or apply the <a href=\"https:\/\/github.com\/curl\/curl\/commit\/8b0744af5b1b631da5b938ca31c3f9895ad5a321\" target=\"_blank\">fix commit<\/a> to a local build. curl&#8217;s <a href=\"https:\/\/curl.se\/docs\/CVE-2026-92392.json\" target=\"_blank\">machine-readable advisory<\/a> also lists fixed versions on three older branches, and the project said it would ship updated <a href=\"https:\/\/rock-solid.curl.dev\/\" target=\"_blank\">Rock-solid curl<\/a> releases, its long-term-support line for customers with support contracts, in step with 8.23.0:<\/p>\n<ul>\n<li>curl and libcurl 8.12.0 through 8.22.0: upgrade to 8.23.0<\/li>\n<li>8.14.x branch: 8.14.3<\/li>\n<li>8.16.x branch: 8.16.2<\/li>\n<li>8.20.x branch: 8.20.2<\/li>\n<li>Debian 13 (trixie): 8.14.1-2+deb13u7 through DSA-6558-1, per <a href=\"https:\/\/security-tracker.debian.org\/tracker\/CVE-2026-92392\" target=\"_blank\">Debian&#8217;s tracker<\/a>. Debian 12 (bookworm) does not carry the vulnerable code.<\/li>\n<\/ul>\n<p>The release fixes 24 CVEs in all. The other 23 are rated Low.<\/p>\n<p>If you cannot update yet, curl&#8217;s advice is not to use HTTP\/2. The <a href=\"https:\/\/curl.se\/docs\/manpage.html#--http11\" target=\"_blank\">&#8211;http1.1<\/a> option asks the tool for HTTP\/1.1, and applications set <a href=\"https:\/\/curl.se\/libcurl\/c\/CURLOPT_HTTP_VERSION.html\" target=\"_blank\">CURLOPT_HTTP_VERSION<\/a> to CURL_HTTP_VERSION_1_1. curl&#8217;s documentation calls that setting a request, because an existing connection on another version may be reused.<\/p>\n<p>HTTP\/2 support in libcurl is a <a href=\"https:\/\/curl.se\/docs\/manpage.html#--http2\" target=\"_blank\">build option<\/a>. A build without it cannot negotiate HTTP\/2, so it cannot reach the upload path the advisory describes.<\/p>\n<h3>How a Hostile Server Turns the Bug Into Code Execution<\/h3>\n<p>Daniel Stenberg, curl&#8217;s lead developer, <a href=\"https:\/\/daniel.haxx.se\/blog\/2026\/10\/14\/a-uaf-turned-rce\/\" target=\"_blank\">explained the bug<\/a> in a post published with the release, and the public report lays out the code path. HTTP\/2 carries several transfers over one connection, and libcurl tracks each transfer with an object it calls an easy handle.<\/p>\n<p>During an upload, the server stalls the transfer by setting the HTTP\/2 window to zero, returning part of the response, and then resetting the stream while keeping the connection open. curl treats the reset as a reason to retry.<\/p>\n<p>In cleanup, curl first tells the HTTP\/2 layer that the transfer is finished, then flushes the rest of the unsent upload into the same connection. With no transfer registered, those leftover bytes are read as a new request. The line pattern the reporter includes in the uploaded file makes them look like request lines. When they do, a new stream is opened that stores a pointer to the easy handle.<\/p>\n<div class=\"separator\" style=\"clear: both;\"><a href=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEh2U4xUHnZVByQi9dRmNa3V-eRSFdVMVfeH8ZXwS0cwANMmo6GS29HTcIid2TUj35EXeicpjXFkKbPZDWLGPabzj_pzl-H2K12Z9zM6aVAxaWCccx8HXLcECQ5utjl_6eL5-cdmJ-XJQ-oySosMkv5WmxUWd_U8vji0YgZwVC5Fr5Y4mDxQgUdjOFGc-M0\/s1700-nu-rw-lo-l85-e365\/curl.png\" style=\"display: block;  text-align: center; clear: left; float: left;\"><img decoding=\"async\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEh2U4xUHnZVByQi9dRmNa3V-eRSFdVMVfeH8ZXwS0cwANMmo6GS29HTcIid2TUj35EXeicpjXFkKbPZDWLGPabzj_pzl-H2K12Z9zM6aVAxaWCccx8HXLcECQ5utjl_6eL5-cdmJ-XJQ-oySosMkv5WmxUWd_U8vji0YgZwVC5Fr5Y4mDxQgUdjOFGc-M0\/s1700-nu-rw-lo-l85-e365\/curl.png\" alt=\"\" border=\"0\" data-original-height=\"1020\" data-original-width=\"2453\"\/><\/a><\/div>\n<p>The retry completes on a new HTTP\/1.1 connection, and the application frees the handle. The old connection still holds the pointer and uses it when the server sends a frame on that stream, which can happen as the program exits.<\/p>\n<p>In the reporter&#8217;s exploit, data the server sends lands in the memory the freed handle had used. A request that goes out leaks local addresses, which the server needs to defeat address space layout randomization (ASLR). A function pointer in that memory is overwritten with bytes from the server, and curl then calls it.<\/p>\n<p>Code execution needs the attacker to know the target&#8217;s exact curl version, architecture, libc allocator and heap layout, to keep two parallel transfers on the right timing, and to fit the payload into about 23 bytes, according to curl&#8217;s advisory. \u00abThe most likely outcome of an attempted attack is rather just a crash,\u00bb Stenberg wrote, putting the chance of success as slim. That is why curl graded the flaw High rather than Critical.<\/p>\n<p>curl uses four severity levels and publishes no <a href=\"https:\/\/curl.se\/dev\/vuln-disclosure.html\" target=\"_blank\">CVSS score<\/a>. The National Vulnerability Database had not analyzed the record as of October 14.<\/p>\n<div class=\"dog_two clear\">\n<div class=\"cf\"><a href=\"https:\/\/thehackernews.uk\/network-defense-d\" rel=\"nofollow noopener sponsored\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"lazyload\" alt=\"Cybersecurity\" src=\"https:\/\/blogger.googleusercontent.com\/img\/b\/R29vZ2xl\/AVvXsEjVV2rRkX8tRMF6gCzemvQNpwFwGxRWxY1cJEYfoLLSj1EZYJOlj5WTR77t0i6kELXujYcaHTpRDqTjCbVHH5Pnh7wzxUiKP5j4dsDkWIMlp2bmpZsL0jeAsA_19pHH5UPtyBvNkZdyGEULOAsXPcraMP5CYjQRFefhXRSdEjYkrdcpUnc4ILcvcdEfAauE\/s728-nu-rw-lo-l85-e365\/tl-d.jpg\" width=\"729\" height=\"91\"\/><\/a><\/div>\n<\/div>\n<p>The fix is a six-line reorder in lib\/multi.c by Stefan Eissing. The HTTP\/2 layer now gives up its references to the handle after the leftover upload data has been flushed, not before.<\/p>\n<p>The report reached curl on September 15 through HackerOne, and the security team confirmed it within hours, according to Stenberg. On <a href=\"https:\/\/daniel.haxx.se\/blog\/2026\/10\/07\/twenty-two-pending-curl-vulnerabilities\/\" target=\"_blank\">October 7<\/a>, the project pre-announced a High-severity fix for the next release, shortening its cycle from eight weeks to six.<\/p>\n<p>curl credits the finding to \u00abLuna with Claude, Anthropic.\u00bb Stenberg names the reporter as Luna Tong of Anthropic, says the finding came through the company&#8217;s new OSS Scanner, and presumes its AI models were involved.<\/p>\n<p>Anthropic opened OSS Scanner on October 8 as an opt-in service that scans enrolled open-source projects with its models and emails the results <a href=\"https:\/\/red.anthropic.com\/oss-scanner\" target=\"_blank\">without human review<\/a>, each report with a reproducer and, where available, a candidate patch. The curl report came three weeks before that public launch. Anthropic&#8217;s <a href=\"https:\/\/www.anthropic.com\/research\/launching-opt-in-vuln-finding-service-for-open-source\" target=\"_blank\">launch post<\/a> quoted Stenberg saying the scanner had turned up \u00abone of the worst curl vulnerabilities reported in the last few years,\u00bb without naming one.<\/p>\n<p>The same maintainer wrote in <a href=\"https:\/\/daniel.haxx.se\/blog\/2025\/07\/14\/death-by-a-thousand-slops\/\" target=\"_blank\">July 2025<\/a> that about a fifth of curl&#8217;s security submissions that year were what he called AI slop, and that only about one in twenty had proved genuine.<\/p>\n<p>curl has spent several years reducing the number of internal pointers to handles in favor of identifiers it looks up when needed, Stenberg wrote, and that is no guarantee against another use-after-free. curl calls the bug a mistake that a memory-safe language would likely have avoided, and the project does not plan to rewrite curl in one.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>A flaw in how curl handles HTTP\/2 uploads lets a malicious server receiving an upload corrupt the client&#8217;s memory, and the researcher who reported it turned that into code execution&hellip;<\/p>\n","protected":false},"author":1,"featured_media":3532,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[2228,10,1677,3778,13,70,1530,57,1730,3088],"class_list":["post-3531","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-clientside","tag-code","tag-curl","tag-demonstrates","tag-execution","tag-flaw","tag-http2","tag-patches","tag-poc","tag-upload"],"_links":{"self":[{"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/posts\/3531","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3531"}],"version-history":[{"count":0,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/posts\/3531\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=\/wp\/v2\/media\/3532"}],"wp:attachment":[{"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3531"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3531"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thedigitalfortress.us\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3531"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}