From b9702f8c487135695ee07a69a24d85e4f7eba40e Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Mon, 15 Jun 2026 12:57:42 +0100 Subject: [PATCH] cookie: use origin scheme for secure context check `Curl_secure_context()` checked `conn->scheme` to determine if Secure cookies may be sent. Since 73daec6, `conn->scheme` is set to the proxy's scheme when using an HTTPS forwarding proxy, causing the function to return TRUE for HTTP origins. This leaked Secure cookies over the plaintext connection between proxy and origin. Use `data->state.origin->scheme` instead, which always reflects the origin's scheme regardless of proxy configuration. Not an approved vulnerability because the regression was introduced after the last release and is not present in any released version. Verified by test 3401 Follow-up to 73daec6620bf9983df89e8df3660bfa3b8fd501d Reported-by: daviey on hackerone URL: https://hackerone.com/reports/3803415 Closes #22024 --- lib/cookie.c | 11 ++++----- lib/cookie.h | 3 +-- lib/http.c | 5 ++-- tests/data/Makefile.am | 1 + tests/data/test3401 | 55 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 tests/data/test3401 diff --git a/lib/cookie.c b/lib/cookie.c index 81d8d1416d..e6a1477058 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -29,6 +29,7 @@ #include "cookie.h" #include "psl.h" #include "curl_trc.h" +#include "transfer.h" #include "slist.h" #include "curl_share.h" #include "strcase.h" @@ -1268,9 +1269,9 @@ static int cookie_sort_ct(const void *p1, const void *p2) return (c2->creationtime > c1->creationtime) ? 1 : -1; } -bool Curl_secure_context(const struct connectdata *conn, const char *host) +bool Curl_secure_context(struct Curl_easy *data, const char *host) { - return conn->scheme->protocol & (CURLPROTO_HTTPS | CURLPROTO_WSS) || + return Curl_xfer_is_secure(data) || curl_strequal("localhost", host) || !strcmp(host, "127.0.0.1") || !strcmp(host, "::1"); @@ -1280,15 +1281,13 @@ bool Curl_secure_context(const struct connectdata *conn, const char *host) * Curl_cookie_getlist * * For a given host and path, return a linked list of cookies that the client - * should send to the server if used now. The secure boolean informs the cookie - * if a secure connection is achieved or not. + * should send to the server if used now. * * It shall only return cookies that have not expired. * * 'okay' is TRUE when there is a list returned. */ CURLcode Curl_cookie_getlist(struct Curl_easy *data, - const struct connectdata *conn, bool *okay, const char *host, struct Curl_llist *list) @@ -1297,7 +1296,7 @@ CURLcode Curl_cookie_getlist(struct Curl_easy *data, const bool is_ip = Curl_host_is_ipnum(host); const size_t myhash = cookiehash(host); struct Curl_llist_node *n; - const bool secure = Curl_secure_context(conn, host); + const bool secure = Curl_secure_context(data, host); struct CookieInfo *ci = data->cookies; const char *path = data->state.up.path; CURLcode result = CURLE_OK; diff --git a/lib/cookie.h b/lib/cookie.h index 77e31b7e73..b8ef8b8ea1 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -109,7 +109,7 @@ struct connectdata; * are only used if the header boolean is TRUE. */ -bool Curl_secure_context(const struct connectdata *conn, const char *host); +bool Curl_secure_context(struct Curl_easy *data, const char *host); CURLcode Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *ci, bool httpheader, @@ -119,7 +119,6 @@ CURLcode Curl_cookie_add(struct Curl_easy *data, const char *path, bool secure) WARN_UNUSED_RESULT; CURLcode Curl_cookie_getlist(struct Curl_easy *data, - const struct connectdata *conn, bool *okay, const char *host, struct Curl_llist *list) WARN_UNUSED_RESULT; void Curl_cookie_clearall(struct CookieInfo *ci); diff --git a/lib/http.c b/lib/http.c index 698ec9627b..e3697b1fa9 100644 --- a/lib/http.c +++ b/lib/http.c @@ -2544,7 +2544,7 @@ static CURLcode http_cookies(struct Curl_easy *data, const char *host = data->req.cookiehost ? data->req.cookiehost : data->state.origin->hostname; Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - result = Curl_cookie_getlist(data, data->conn, &okay, host, &list); + result = Curl_cookie_getlist(data, &okay, host, &list); if(!result && okay) { struct Curl_llist_node *n; size_t clen = 8; /* hold the size of the generated Cookie: header */ @@ -3517,7 +3517,6 @@ static CURLcode http_header_s(struct Curl_easy *data, const char *hd, size_t hdlen) { #if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_HSTS) - struct connectdata *conn = data->conn; const char *v; #else (void)data; @@ -3533,7 +3532,7 @@ static CURLcode http_header_s(struct Curl_easy *data, * real peer hostname. */ const char *host = data->req.cookiehost ? data->req.cookiehost : data->state.origin->hostname; - const bool secure_context = Curl_secure_context(conn, host); + const bool secure_context = Curl_secure_context(data, host); CURLcode result; Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); result = Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host, diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 0a52bcc7f9..0d5277d55b 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -286,6 +286,7 @@ test3216 test3217 test3218 test3219 test3220 test3221 test3222 \ test3300 test3301 test3302 test3303 test3304 test3305 \ \ test3400 \ +test3401 \ \ test4000 test4001 diff --git a/tests/data/test3401 b/tests/data/test3401 new file mode 100644 index 0000000000..0c88738ec2 --- /dev/null +++ b/tests/data/test3401 @@ -0,0 +1,55 @@ + + + + +HTTP +HTTPS proxy +cookies +Secure + + + +# Server-side + + +HTTP/1.1 200 OK +Content-Length: 4 + +foo + + + +# Client-side + + +http +https-proxy + + +HTTPS-proxy +cookies + + +HTTP via HTTPS proxy does not send Secure cookies + + +-x https://%HOSTIP:%HTTPSPROXYPORT --proxy-insecure -b %LOGDIR/jar%TESTNUMBER.txt http://test.example/%TESTNUMBER + + +# Netscape HTTP Cookie File +test.example FALSE / TRUE 9999999999 session secret + + + +# Verify data after the test has been "shot" + + +GET http://test.example/%TESTNUMBER HTTP/1.1 +Host: test.example +User-Agent: curl/%VERSION +Accept: */* +Proxy-Connection: Keep-Alive + + + +