Cross‑origin cookies leak and injection risk when using a custom Host header
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 HackerOneReport Stats
- Report ID: 3516878
- State: Closed
- Substate: not-applicable
- Upvotes: 28