Reproducing DEBIAN-CVE-2026-94265 (curl auth leak on redirect)
curl / libcurl
| Version type | Vulnerable | Fixed |
|---|---|---|
| Releases | 8.21.0 - 8.22.0 | 8.23.0 |
| Tested builds | 8.23.0-DEV | 8.23.1-DEV |
| Catalog | Fixed in fork | Fork branch | Merged |
|---|---|---|---|
| Severity | Low | Updated |
| Advisory | |
|---|---|
| Fixes | |
| Code | |
| Discussion |
Setup
curl sends an NTLM Authorization header to a different origin after a redirect in this reproduction.
| Vulnerable | upstream at d1317b5, reports 8.23.0-DEV |
|---|---|
| Fixed | our fork at ce57339, reports 8.23.1-DEV |
| Build | same flags both sides |
| Sandbox | no network, loopback only |
The vulnerable build allowed NTLM authentication with a server on a different origin. Upstream fix 557a52f, included in the fork, restricts NTLM and Negotiate to the origin of the first request unless you pass --location-trusted.
Server A demands NTLM, then redirects to a userinfo URL on a different port, making it a foreign origin. Server B records any Authorization header it receives. An NTLM header at B is the failure this repro checks.
Reproduce (vulnerable build)
docker run --rm --network none --pids-limit 64 --memory 512m --read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m cve-94265-demo python3 /task/repro.py /opt/tree-vuln/bin/curl$ LD_LIBRARY_PATH=/opt/tree-vuln/lib /opt/tree-vuln/bin/curl --version | head -1
curl 8.23.0-DEV (x86_64-pc-linux-gnu) libcurl/8.23.0-DEV OpenSSL/3.5.7
$ LD_LIBRARY_PATH=/opt/tree-vuln/lib /opt/tree-vuln/bin/curl -v --ntlm --user testuser:testpass --location --max-time 20 http://127.0.0.1:8000/r1
AAAAAAAAAAAAAAAhoIBAFpkQwKRCZFMhjj0tw47wEjKHRHlvzfxQamFcheMuv8v+xeqphEO5V41xRd7R9deOXRlc3R1c2VyV09SS1NUQVRJT04=
> User-Agent: curl/8.23.0-DEV
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Server: BaseHTTP/0.6 Python/3.13.5
< Date: Wed, 28 Oct 2026 18:02:54 GMT
< Location: http://bob:alice@127.0.0.1:9000/r2
< Content-Length: 11
< Connection: close
<
0 11 0 0 0 0 0 0 0
* shutting down connection #0
* Issue another request to this URL: 'http://bob:alice@127.0.0.1:9000/r2'
* NTLM picked AND auth done set, clear picked
* Trying 127.0.0.1:9000...
* Established connection to 127.0.0.1 (127.0.0.1 port 9000) from 127.0.0.1 port 33132
0 0 0 0 0 0 0 0 0* using HTTP/1.x
* Server auth using NTLM with user 'bob'
> GET /r2 HTTP/1.1
> Host: 127.0.0.1:9000
> Authorization: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAA=
> User-Agent: curl/8.23.0-DEV
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: BaseHTTP/0.6 Python/3.13.5
< Date: Wed, 28 Oct 2026 18:02:54 GMT
< Content-Type: text/plain
< Content-Length: 6
< Connection: close
<
{ [6 bytes data]
100 6 100 6 0 0 5763 0 0
100 6 100 6 0 0 5597 0 0
100 6 100 6 0 0 5444 0 0
* shutting down connection #1
req1: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAA...
req2: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAA...
req1: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAA...Regression test 5031 shows the same header leak.
docker run --rm --network none --pids-limit 64 --memory 1g cve-94265-demo sh -c 'cp /src/fixed/tests/data/test5031 /src/vuln/tests/data/test5031 && cd /src/vuln && make -C tests/server >/tmp/srv.log 2>&1 && cd tests && perl runtests.pl 5031 2>&1 | tail -n 20' 5031: protocol FAILED:
@@ -12,6 +12,7 @@
[CR][LF]
GET /50310002 HTTP/1.1[CR][LF]
Host: example.org:9000[CR][LF]
+Authorization: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAA=[CR][LF]
User-Agent: curl/8.23.0-DEV[CR][LF]
Accept: */*[CR][LF]
[CR][LF]
FAIL 5031: 'NTLM redirect with userinfo must not send NTLM' HTTP, HTTP GET, HTTP NTLM auth, NTLM, followlocationVerify (fork-fixed build)
Run the same repro against the fork build.
docker run --rm --network none --pids-limit 64 --memory 512m --read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m cve-94265-demo python3 /task/repro.py /opt/tree-fixed/bin/curl$ LD_LIBRARY_PATH=/opt/tree-fixed/lib /opt/tree-fixed/bin/curl --version | head -1
curl 8.23.1-DEV (x86_64-pc-linux-gnu) libcurl/8.23.1-DEV OpenSSL/3.5.7
$ LD_LIBRARY_PATH=/opt/tree-fixed/lib /opt/tree-fixed/bin/curl -v --ntlm --user testuser:testpass --location --max-time 20 http://127.0.0.1:8000/r1
T /r1 HTTP/1.1
> Host: 127.0.0.1:8000
> Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAABwAAAACAAIAHAAAAALAAsAeAAAAAAAAAAAAAAAhoIBAFpkQwKRCZFMhjj0tw47wEjKHRHlvzfxQamFcheMuv8v+xeqphEO5V41xRd7R9deOXRlc3R1c2VyV09SS1NUQVRJT04=
> User-Agent: curl/8.23.1-DEV
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Server: BaseHTTP/0.6 Python/3.13.5
< Date: Wed, 28 Oct 2026 18:02:55 GMT
< Location: http://bob:alice@127.0.0.1:9000/r2
< Content-Length: 11
< Connection: close
<
0 11 0 0 0 0 0 0 0
* shutting down connection #0
* Issue another request to this URL: 'http://bob:alice@127.0.0.1:9000/r2'
* NTLM picked AND auth done set, clear picked
* Trying 127.0.0.1:9000...
* Established connection to 127.0.0.1 (127.0.0.1 port 9000) from 127.0.0.1 port 33140
0 0 0 0 0 0 0 0 0> GET /r2 HTTP/1.1
> Host: 127.0.0.1:9000
> User-Agent: curl/8.23.1-DEV
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: BaseHTTP/0.6 Python/3.13.5
< Date: Wed, 28 Oct 2026 18:02:55 GMT
< Content-Type: text/plain
< Content-Length: 6
< Connection: close
<
{ [6 bytes data]
100 6 100 6 0 0 5176 0 0
100 6 100 6 0 0 5029 0 0
100 6 100 6 0 0 4901 0 0
* shutting down connection #1
req1: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAA...
req2: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAA...
req1: <absent>The redirect still completes (final 200, 6 bytes), and server B receives no Authorization header.
The regression test passes on the fixed tree.
docker run --rm --network none --pids-limit 64 --memory 1g cve-94265-demo sh -c 'cd /src/fixed && make -C tests/server >/tmp/srv.log 2>&1 && cd tests && perl runtests.pl 5031 2>&1 | tail -n 6'* Servers: HTTP-IPv6 HTTP-unix FTP-IPv6
*****************************************
test 5031 [NTLM redirect with userinfo must not send NTLM]
--p----e--- OK (1 out of 1 , remaining: 00:00, took 1.078s, duration: 00:01)
TESTDONE: 1 tests were considered during 1 seconds.
TESTDONE: 1 tests out of 1 reported OK: 100%Limits
NTLM stands in for Negotiate here: same gate, and the sandbox has no KDC. Trigger is --location without --location-trusted against a server that answers 401, then redirects to a userinfo URL.
Attack flow
Agent runbook
docker run --rm --network none --pids-limit 64 --memory 512m --read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m cve-94265-demo python3 /task/repro.py /opt/tree-vuln/bin/curl
docker run --rm --network none --pids-limit 64 --memory 1g cve-94265-demo sh -c 'cp /src/fixed/tests/data/test5031 /src/vuln/tests/data/test5031 && cd /src/vuln && make -C tests/server >/tmp/srv.log 2>&1 && cd tests && perl runtests.pl 5031 2>&1 | tail -n 20'
docker run --rm --network none --pids-limit 64 --memory 512m --read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m cve-94265-demo python3 /task/repro.py /opt/tree-fixed/bin/curl
docker run --rm --network none --pids-limit 64 --memory 1g cve-94265-demo sh -c 'cd /src/fixed && make -C tests/server >/tmp/srv.log 2>&1 && cd tests && perl runtests.pl 5031 2>&1 | tail -n 6'Release information
| Source | Official advisory |
|---|---|
| Checked | |
| Severity | Low |
| Weakness | CWE-200 |
Recorded evidence
| upstream fix present in fork base 8.23.1-DEV | |
| regression test tests/data/test5031 executed RED then GREEN | |
| test-only branch, fork-only push |
Status history
| Date | Status | Record |
|---|---|---|
| Fixed in fork | merged to fork master b370f63 |