All posts

Reproducing DEBIAN-CVE-2026-94265 (curl auth leak on redirect)

curl / libcurl

Versions
Version typeVulnerableFixed
Releases8.21.0 - 8.22.08.23.0
Tested builds8.23.0-DEV8.23.1-DEV
Status
Catalog
Fixed in fork
Fork branchMerged
SeverityLowUpdated
Related links
Advisory
Official advisoryOSV recordCatalog record
Fixes
Upstream fixFork mergeFork branch
Code
Vulnerable sourceFixed sourceFork repository
Discussion
Original report and discussion

Setup

curl sends an NTLM Authorization header to a different origin after a redirect in this reproduction.

Vulnerableupstream at d1317b5, reports 8.23.0-DEV
Fixedour fork at ce57339, reports 8.23.1-DEV
Buildsame flags both sides
Sandboxno 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)

Command
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
Output
$ 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
--- exit: 0
--- curl -v stderr (tail):
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

--- server A Authorization headers seen:
req1: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAA...
req2: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAA...
--- server B Authorization headers seen:
req1: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAA...
RED - NTLM Authorization re-transmitted to foreign origin

Regression test 5031 shows the same header leak.

Command
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'
Output
 5031: protocol FAILED:
--- log/check-expected
+++ log/check-generated
@@ -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, followlocation

Verify (fork-fixed build)

Run the same repro against the fork build.

Command
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
Output
$ 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
--- exit: 0
--- curl -v stderr (tail):
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

--- server A Authorization headers seen:
req1: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAA...
req2: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAA...
--- server B Authorization headers seen:
req1: <absent>
GREEN - no auth forwarded to foreign origin

The redirect still completes (final 200, 6 bytes), and server B receives no Authorization header.

The regression test passes on the fixed tree.

Command
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'
Output
* 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

Client logs in to server A with --ntlm (127.0.0.1:8000)
Server A answers 301 to a userinfo URL on a foreign origin (127.0.0.1:9000)
curl follows the redirect with --location
Vulnerable: NTLM Authorization re-transmitted to server B (RED)
Fixed: second request carries no Authorization, redirect still completes (GREEN)

Agent runbook

Agent runbook - run in order
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

SourceOfficial advisory
Checked
SeverityLow
WeaknessCWE-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

DateStatusRecord
Fixed in forkmerged to fork master b370f63