HexBrain

curl · Report #3803415

Secure cookies leaked to HTTP origins through HTTPS forwarding proxy

N/Astatus
15upvotes
15 Jun 2026disclosed

Summary

A regression in commit 73daec6 caused Curl_secure_context() to use the proxy's HTTPS scheme instead of the origin's scheme when forwarding through an HTTPS proxy, leaking Secure cookies to HTTP origins in cleartext. Fix in PR #22024.

Closed as "Not Applicable" as the regression was not present in any release, only origin/master

How it was found

Summary:

When curl accesses an http:// origin through an HTTPS forwarding proxy, it sends Secure cookies in the request. The cookies travel in cleartext between the proxy and the origin server, visible to the proxy operator and anyone on that network path. curl also reports CURLINFO_SCHEME as "https" to the application for what is an http:// transfer, which can mislead application-level security logic.

This is a regression introduced on 2026-06-12 in commit 73daec6 (PR #21967). proxy.c:652 sets conn->scheme to the proxy's HTTPS scheme. Curl_secure_context() (cookie.c:1273) checks conn->scheme->protocol & CURLPROTO_HTTPS and returns TRUE, so Secure cookies are included. Before this commit, conn->scheme held the origin's scheme and Secure cookies were correctly withheld.

The same conn->scheme change causes url.c:2505 to report CURLINFO_SCHEME as "https" for an http:// origin.

Affected version

$ curl  --version
curl 8.21.0-DEV (Linux) libcurl/8.21.0-DEV OpenSSL/3.0.20 zlib/1.2.13 brotli/1.0.9 zstd/1.5.4 libpsl/0.21.2 nghttp2/1.52.0
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt mqtts pop3 pop3s rtsp smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTPS-proxy IPv6 Largefile libz PSL SSL threadsafe TLS-SRP UnixSockets zstd

Only affected since commit 73daec6 (2026-06-12). No released version is affected. Still present on origin/master at 79a2416 as of 2026-06-15.

Steps To Reproduce:

A self-contained Dockerfile and patch (fix.patch) are attached. The Dockerfile builds three curl binaries from source: pre-regression (c951368), regression (bb837dd), and regression with the suggested fix applied. It also runs a Squid HTTPS forwarding proxy and a plain HTTP origin server that logs received cookies.

docker build -t cookie-proxy .
docker run --rm -it cookie-proxy

Inside the container, test each binary:

curl-safe  -sv -x https://127.0.0.1:8443 --proxy-insecure -b /tmp/cookies.txt http://test.example:8080/path
curl-vuln  -sv -x https://127.0.0.1:8443 --proxy-insecure -b /tmp/cookies.txt http://test.example:8080/path
curl-fixed -sv -x https://127.0.0.1:8443 --proxy-insecure -b /tmp/cookies.txt http://test.example:8080/path

Check what the origin received:

tail /tmp/origin.log

curl-vuln leaks the Secure cookie (the verbose output includes a Cookie: header, and the origin log confirms receipt). curl-safe and curl-fixed withhold it (no Cookie: header, origin log shows RECEIVED no Cookie header).

Suggested fix

A patch is attached (fix.patch). Curl_secure_context() should check data->state.origin->scheme instead of conn->scheme. The refactor already migrated most security checks to data->state.origin but missed this function. The conn->scheme assignment at proxy.c:652 is still needed for SSL filter setup, so it should stay, but Curl_secure_context() should not read it. Curl_xfer_is_secure() is not affected because it has an additional Curl_conn_is_ssl() check that correctly excludes proxy SSL filters (cfilters.c:693).

Impact

Secure cookies (session tokens, auth cookies, CSRF tokens) are sent in cleartext over the HTTP connection between the HTTPS proxy and the origin server. Anyone who can observe that network path can read them. The proxy operator can harvest them regardless. The CURLINFO_SCHEME misreporting can also trick application-level security checks (e.g. "only allow this action over HTTPS") into treating an insecure transfer as secure.

The bug affects all HTTP methods (GET, HEAD, POST, PUT, DELETE, PATCH, etc.) because the Secure context check runs in Curl_cookie_getlist (cookie.c:1300), which is called from the request header construction path for every method. WebSocket upgrade requests (ws:// through the proxy) are also affected. Any libcurl application using the cookie engine (CURLOPT_COOKIEFILE / CURLOPT_COOKIEJAR) through an HTTPS proxy is affected, not just the curl CLI.

RFC violated: RFC 6265 Section 5.4 step 3 ties "secure channel" to the https URI scheme (RFC 7230 Section 2.7.2). The request uses http://, so Secure cookies must not be sent regardless of the TLS transport to the proxy.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original