Description
## 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](https://github.com/curl/curl/commit/73daec6620bf9983df89e8df3660bfa3b8fd501d) ([PR #21967](https://github.com/curl/curl/pull/21967)). [proxy.c:652](https://github.com/curl/curl/blob/bb837dd/lib/proxy.c#L652) sets `conn->scheme` to the proxy's HTTPS scheme. `Curl_secure_context()` ([cookie.c:1273](https://github.com/curl/curl/blob/bb837dd/lib/cookie.c#L1273)) 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](https://github.com/curl/curl/blob/bb837dd/lib/url.c#L2505) 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](https://github.com/curl/curl/commit/73daec6620bf9983df89e8df3660bfa3b8fd501d) (2026-06-12). No released version is affected. Still present on origin/master at [79a2416](https://github.com/curl/curl/commit/79a24161ab) 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.
```bash
docker build -t cookie-proxy .
docker run --rm -it cookie-proxy
```
Inside the container, test each binary:
```bash
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:
```bash
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](https://github.com/curl/curl/blob/bb837dd/lib/proxy.c#L652) 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](https://github.com/curl/curl/blob/bb837dd/lib/cfilters.c#L693)).
## 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](https://github.com/curl/curl/blob/bb837dd/lib/cookie.c#L1300)), 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](https://datatracker.ietf.org/doc/html/rfc6265#section-5.4) Section 5.4 step 3 ties "secure channel" to the `https` URI scheme ([RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-2.7.2) Section 2.7.2). The request uses `http://`, so Secure cookies must not be sent regardless of the TLS transport to the proxy.
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](https://github.com/curl/curl/commit/73daec6620bf9983df89e8df3660bfa3b8fd501d) ([PR #21967](https://github.com/curl/curl/pull/21967)). [proxy.c:652](https://github.com/curl/curl/blob/bb837dd/lib/proxy.c#L652) sets `conn->scheme` to the proxy's HTTPS scheme. `Curl_secure_context()` ([cookie.c:1273](https://github.com/curl/curl/blob/bb837dd/lib/cookie.c#L1273)) 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](https://github.com/curl/curl/blob/bb837dd/lib/url.c#L2505) 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](https://github.com/curl/curl/commit/73daec6620bf9983df89e8df3660bfa3b8fd501d) (2026-06-12). No released version is affected. Still present on origin/master at [79a2416](https://github.com/curl/curl/commit/79a24161ab) 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.
```bash
docker build -t cookie-proxy .
docker run --rm -it cookie-proxy
```
Inside the container, test each binary:
```bash
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:
```bash
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](https://github.com/curl/curl/blob/bb837dd/lib/proxy.c#L652) 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](https://github.com/curl/curl/blob/bb837dd/lib/cfilters.c#L693)).
## 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](https://github.com/curl/curl/blob/bb837dd/lib/cookie.c#L1300)), 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](https://datatracker.ietf.org/doc/html/rfc6265#section-5.4) Section 5.4 step 3 ties "secure channel" to the `https` URI scheme ([RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-2.7.2) Section 2.7.2). The request uses `http://`, so Secure cookies must not be sent regardless of the TLS transport to the proxy.
Basic Information
ID
H1:3803415
Published
Jun 15, 2026 at 11:37
Modified
Jun 15, 2026 at 13:48