Cross‑origin cookies leak and injection risk when using a custom Host header

Disclosed: 2026-01-20 06:48:30 By b4c90000040c1287364ccde6de680 To curl
Unknown
Vulnerability Details
## Summary When a custom hostname is specified, it is used for cookie matching if the cookie engine is also enabled for this transfer. This matching persists in cross-origin redirects despite that the originally supplied hostname is removed. cookiehost is set from a custom Host header: `lib/http.c http_set_aptr_host` ```c ptr = Curl_checkheaders(data, STRCONST("Host")); if(ptr && (!data->state.this_is_a_follow || curl_strequal(data->state.first_host, conn->host.name))) { /* If we have a given custom Host: header, we extract the hostname in order to possibly use it for cookie reasons later on. We only allow the custom Host: header if this is NOT a redirect, as setting Host: in the redirected request is being out on thin ice. Except if the hostname is the same as the first one! */ char *cookiehost; CURLcode result = copy_custom_value(ptr, &cookiehost); ... aptr->cookiehost = cookiehost; } ``` cookiehost is used for both sending cookies and processing Set-Cookie: `lib/http.c http_header_s` ```c v = (data->cookies && data->state.cookie_engine) ? HD_VAL(hd, hdlen, "Set-Cookie:") : NULL; ... /* If there is a custom-set Host: name, use it here, or else use * real peer hostname. */ const char *host = data->state.aptr.cookiehost ? data->state.aptr.cookiehost : conn->host.name; ... result = Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host, data->state.up.path, secure_context); ``` `lib/http.c http_cookies` ```c const char *host = data->state.aptr.cookiehost ? data->state.aptr.cookiehost : data->conn->host.name; Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); result = Curl_cookie_getlist(data, data->conn, &okay, host, &list); ``` Since cookiehost is not cleared on redirects this behaviour persists across cross-origin redirects. libcurl documentation on CURLOPT_HTTPHEADER [1]: ``` The specified hostname is used for cookie matching if the cookie engine is also enabled for this transfer.... ``` But contains no explicit warning that this also applies in cross-origin redirects. ## Affected version Tested on curl 8.18.0 ## Reproduction ``` user@pc:~$ curl -v -L -c cookies.txt -H "Host: example.com" --resolve b.com:8001:127.0.0.1 --resolve a.com:8000:127.0.0.1 a.com:8000 * Added b.com:8001:127.0.0.1 to DNS cache * Added a.com:8000:127.0.0.1 to DNS cache * Hostname a.com was found in DNS cache * Trying 127.0.0.1:8000... * Established connection to a.com (127.0.0.1 port 8000) from 127.0.0.1 port 56874 * using HTTP/1.x > GET / HTTP/1.1 > Host: example.com > User-Agent: curl/8.18.0 > Accept: */* > * Request completely sent off * HTTP 1.0, assume close after body < HTTP/1.0 302 Found < Server: BaseHTTP/0.6 Python/3.12.3 < Date: Mon, 19 Jan 2026 12:35:05 GMT < Location: http://b.com:8001/ * Added cookie ccc="secret" for domain example.com, path /, expire 0 < Set-Cookie: ccc=secret; Path=/ < Content-Length: 0 < * shutting down connection #0 * Clear auth, redirects to port from 8000 to 8001 * Issue another request to this URL: 'http://b.com:8001/' * Hostname b.com was found in DNS cache * Trying 127.0.0.1:8001... * Established connection to b.com (127.0.0.1 port 8001) from 127.0.0.1 port 43966 * using HTTP/1.x > GET / HTTP/1.0 > Host: b.com:8001 > User-Agent: curl/8.18.0 > Accept: */* > Cookie: ccc=secret > * Request completely sent off * HTTP 1.0, assume close after body < HTTP/1.0 302 Found < Server: BaseHTTP/0.6 Python/3.12.3 < Date: Mon, 19 Jan 2026 12:35:05 GMT * Added cookie bbb="test" for domain example.com, path /, expire 0 < Set-Cookie: bbb=test; Path=/ < Location: http://a.com:8000/check < Content-Length: 0 < * shutting down connection #1 * Clear auth, redirects to port from 8001 to 8000 * Issue another request to this URL: 'http://a.com:8000/check' * Hostname a.com was found in DNS cache * Trying 127.0.0.1:8000... * Established connection to a.com (127.0.0.1 port 8000) from 127.0.0.1 port 56882 * using HTTP/1.x > GET /check HTTP/1.0 > Host: example.com > User-Agent: curl/8.18.0 > Accept: */* > Cookie: bbb=test; ccc=secret > * Request completely sent off * HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Server: BaseHTTP/0.6 Python/3.12.3 < Date: Mon, 19 Jan 2026 12:35:05 GMT < Content-Length: 0 < * shutting down connection #2 ``` ``` user@pc:~$ cat cookies.txt # Netscape HTTP Cookie File # https://curl.se/docs/http-cookies.html # This file was generated by libcurl! Edit at your own risk. example.com FALSE / FALSE 0 bbb test example.com FALSE / FALSE 0 ccc secret ``` ## References [1] https://curl.se/libcurl/c/CURLOPT_HTTPHEADER.html ## Impact cross‑origin cookies leak and injection risk
Actions
View on HackerOne
Report Stats
  • Report ID: 3516878
  • State: Closed
  • Substate: not-applicable
  • Upvotes: 28
Share this report