Engineering research / security

curl 8.23.0 Fixes 24 Vulnerabilities: One High-Severity HTTP/2 Use-After-Free, a Cluster of Credential-Scoping Bugs, and How to Triage libcurl in Your Fleet

curl 8.23.0, released 14 October 2026, fixes 24 vulnerabilities. One is rated high: an HTTP/2 upload use-after-free. Many of the low ones send credentials or reuse authenticated connections across origins. Which apply to you depends on features, so triage by usage, not by headline count.

By Sandeep Belgavi · Published 2026-10-25 · Prepared 2026-10-21

Recent development · Practical technical guide · 21 October 2026

curl 8.23.0, released 14 October 2026, fixes 24 vulnerabilities. One is rated high: an HTTP/2 upload use-after-free. Many of the low ones send credentials or reuse authenticated connections across origins. Which apply to you depends on features, so triage by usage, not by headline count.

The release

curl 8.23.0 was released on 14 October 2026. Its maintainer's release post counts four changes, 281 bug fixes and 24 security fixes, and says they were too many to list individually, pointing to the security page instead. The changes include the removal of SMB and SMBS support and the deprecation of CURL_GLOBAL_WIN32 in favour of CURL_GLOBAL_WINSOCK. If anything in your estate fetches smb:// URLs through curl, it stops working with this version.

Twenty-four advisories in one release is unusual, and the number invites either panic or fatigue. Neither helps. Each advisory states the affected version range, whether the command-line tool is affected, and the conditions under which the bug matters. Most of them need a specific feature: Negotiate authentication, an HTTP proxy, Schannel client certificates, a bound interface. The useful question is which features your callers use.

The one rated high

CVE-2026-92392 is a use-after-free during HTTP/2 uploads when the server sends RST_STREAM with HTTP_1_1_REQUIRED or REFUSED_STREAM. It affects 8.12.0 through 8.22.0, both libcurl and the tool, and it is the only advisory in the batch rated high. The advisory states that it has been shown convertible into remote code execution when a malicious server meets a long list of conditions, among them knowledge of the exact curl version and structure layout, the architecture, a compatible allocator and heap layout, specific TLS behaviour, two parallel transfers with calibrated timing, and a short command constraint of about 23 bytes. That list is an honest description of difficulty, not a reason to wait: any client that uploads over HTTP/2 to servers it does not fully control, such as webhooks, user-supplied endpoints or crawlers, is in scope.

Credentials that cross origins

A group of the low-severity advisories share one theme: authentication state that leaks to a host it was not meant for. Read them together, because the fix for your architecture is the same.

AdvisoryWhat leaks or mixesAffected rangeNeeds
CVE-2026-94265Negotiate (Kerberos) authorization sent after a redirect to a URL with userinfo8.21.0 to 8.22.0Negotiate plus following redirects
CVE-2026-86413Negotiate credential details passed to a redirected, unrelated origin8.21.0 to 8.22.0Ambient-user Negotiate plus redirects
CVE-2026-87861Request sent over a connection authenticated with Negotiate for another origin8.21.0 to 8.22.0Ambient-user Negotiate, connection reuse
CVE-2026-86414Origin credentials sent to the HTTP proxy when it answers CONNECT with 4017.10.8 to 8.22.0An HTTP proxy you do not trust
CVE-2026-86415Cached Schannel connection with an automatic client certificate reused after a redirect8.21.0 to 8.22.0Schannel on Windows, client certificates
CVE-2026-107929Connection bound to one interface or source address reused for another8.9.0 to 8.22.0CURLOPT_INTERFACE with if!, host! or ifhost!
CVE-2026-94266Credentials appear in CURLINFO_EFFECTIVE_URL although neither URL contained them7.62.0 to 8.22.0Code that logs the effective URL
CVE-2026-86409An AWS SigV4 Authorization header still sent after setting the option to NULL7.75.0 to 8.21.0Reusing an easy handle across SigV4 and other requests

Three of the Negotiate bugs were introduced in 8.21.0, so older builds are not affected by those; the proxy leak goes back to 7.10.8. The SigV4 advisory lists 8.21.0 as its last affected version. Several advisories also list fixed releases on older branches, such as 8.20.2, 8.16.2 and 8.14.3, which matters for distributions that backport rather than upgrade.

Triage by feature, not by count

Inventory where libcurl lives before you count CVEs. It is in the operating system package, in language bindings, inside git for HTTP transport, statically linked into applications, and inside container base images that nobody rebuilt this month. Then map each caller to the features it uses. The table above becomes a small function you can run over an inventory:

Covers only the advisories discussed here; extend the table from the security page for a complete check.

ADVISORIES = [
    # (cve, first affected, last affected, features that must all be in use)
    ("CVE-2026-92392", (8, 12, 0), (8, 22, 0), {"http2", "upload"}),
    ("CVE-2026-94265", (8, 21, 0), (8, 22, 0), {"negotiate", "redirects"}),
    ("CVE-2026-86413", (8, 21, 0), (8, 22, 0), {"negotiate", "redirects"}),
    ("CVE-2026-87861", (8, 21, 0), (8, 22, 0), {"negotiate"}),
    ("CVE-2026-86414", (7, 10, 8), (8, 22, 0), {"http_proxy"}),
    ("CVE-2026-86415", (8, 21, 0), (8, 22, 0), {"schannel", "client_cert"}),
    ("CVE-2026-107929", (8, 9, 0), (8, 22, 0), {"bound_interface"}),
    ("CVE-2026-94266", (7, 62, 0), (8, 22, 0), {"logs_effective_url"}),
    ("CVE-2026-86409", (7, 75, 0), (8, 21, 0), {"sigv4"}),
]

def applicable(version, features):
    v = tuple(int(x) for x in version.split("."))
    return [cve for cve, lo, hi, needs in ADVISORIES if lo <= v <= hi and needs <= features]

fleet = {
    "webhook-sender (8.22.0)": ("8.22.0", {"http2", "upload", "redirects"}),
    "intranet-sync (8.21.1)": ("8.21.1", {"negotiate", "redirects", "http_proxy"}),
    "s3-backup (8.11.1)": ("8.11.1", {"sigv4", "upload"}),
    "health-probe (8.23.0)": ("8.23.0", {"http2"}),
}
for name, (version, features) in fleet.items():
    print(name, applicable(version, features))

For this synthetic fleet the output is: the webhook sender is exposed to the high-severity HTTP/2 upload bug; the intranet sync job to all three Negotiate bugs and the proxy leak, four in total; the backup job, on 8.11.1, to the SigV4 bug; the probe, already on 8.23.0, to none. Four services, four different urgencies, and the order of patching follows directly.

Mitigations while you patch

  • Upgrade to 8.23.0, or to the fixed release of your distribution branch named in each advisory.
  • For the HTTP/2 upload bug, uploads to untrusted servers can be forced to HTTP/1.1 until patched; measure the performance cost first.
  • Do not follow redirects when using Negotiate; the advisory recommends exactly that.
  • Avoid HTTP proxies you do not control, as the proxy advisory recommends.
  • Never log CURLINFO_EFFECTIVE_URL unredacted.
  • Rebuild container images; a patched host does not patch the libcurl inside an image.

Verification

Confirm the version every caller actually loads, not the one the package manager reports: curl -V for the tool, the binding's own version call for libraries, and a software bill of materials scan for images and static binaries. For the redirect and proxy bugs, a staging test with a local server that redirects to a second host and records the Authorization header shows whether a given client leaks before and after the upgrade.

Sources and scope

Checked against these sources on 21 October 2026. Event: curl 8.23.0 and 24 security advisories, 14 October 2026; recheck it before acting. Examples and figures are illustrative, not measurements.

Inventory every libcurl copy, map callers to the features each advisory needs, patch the HTTP/2 upload and credential-scoping exposures first, and rebuild container images.