HexBrain

curl · Report #4127756

urlapi: CURLUPART_HOST accepts text after an IPv6 zone ip and URL round trip changes the host

N/Astatus
lowseverity
5upvotes
19 Oct 2026disclosed

How it was found

Summary:

[six or fewer sentences describing the issue in your own human voice and optionally a short proof-of-concept script] An app can set a host from untrusted input from CURLUPART_HOST, as the docs allow, and rely on curl to reject bad hosts. curl accepts [fe80::1%25eth0]@evil.example/x as a valid IPv6 host. The URL it then builds has evil.example as its host. Any code that uses that URL string goes to evil.example. libcurl also sends the follow-up request there after a relative redirect from the IPv6 server. An attack needs an app that sets untrusted hosts this way, and i do not know of one.

Affected version

[Which curl/libcurl version are you using to reproduce? On which platform? curl -V typically generates good output to include] curl 8.10.0 through 8.23.0

Steps To Reproduce:

[add details for how we can reproduce the issue] Paste this: 1. Build libcurl 8.10.0 or later (I tested 8.10.0, 8.23.0, and master c4b341c). 2. Save the program from the report as repro.c. 3. Compile it:

cc repro.c -I<curl>/include -L<curl>/lib -lcurl -o repro
  1. Run ./repro.

Expected: curl_url_set() rejects the host, the same way it rejects [::1]junk with CURLUE_BAD_HOSTNAME.

Actual:

set host: rc=0
host:     [fe80::1%25eth0]@evil.example/x
url:      http://[fe80::1%25eth0]@evil.example/%25eth0]/
reparse:  rc=0 host=evil.example

Redirect case

  1. Start an HTTP server on [::1]:18934 that answers 302 with Location: /next.
  2. Start any HTTP server on 127.0.0.1:18933.
  3. Set the host to [::1%25lo0]@127.0.0.1:18933/x and the port to 18934. On Linux, use lo in place of lo0.
  4. Pass the handle with CURLOPT_CURLU, set CURLOPT_FOLLOWLOCATION to 1, and run the transfer.
  5. The first request goes to [::1]:18934. The second request goes to 127.0.0.1:18933.

Again: there is no bug-bounty for curl. We do not offer any rewards, only proper credits.

Impact

Summary:

curl accepts [fe80::1%25eth0]@evil.example/x as a valid IPv6 host. curl_url_get(CURLUPART_URL) then gives a URL whose host is evil.example. Any code that logs, stores, or fetches that URL uses the wrong host. With CURLOPT_CURLU and CURLOPT_FOLLOWLOCATION, libcurl sends the first request to the IPv6 address. A relative redirect from that server sends the next request to the other host and port. An attack needs an app that passes untrusted hosts to CURLUPART_HOST

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original