curl · Report #4112912
CVE-2026-111481: server-set cookie still aborts cookie jar
How it was found
Suggested CWE: CWE-1284: Improper Validation of Specified Quantity in Input (H1 didn't let me chose this)
AI Disclaimer:
I've written this report with the help of AI, please feel free to let me know if I made a mistake, I've read the final revision of this report a few times to ensure it was solid but my understanding of the inner workings of curl is where I can fall short.
Summary:
The fix for CVE-2026-92386 (445aa87e13) lets the cookie file parser accept lines up to MAX_COOKIE_LINE + 48 bytes, so a line of 5047 or more characters still fails to load. A saved cookie line also holds the domain and the path, and neither counts toward the Set-Cookie length limit when the server leaves them out of the header. A server can set a cookie with a 4000-byte value and no Path, at a URL with a 1500-byte path, and curl saves a 5539-character line. Since 3f0629ca4 (8.18.0), a cookie file load error fails the transfer: the next curl run that loads the jar fails at once with "(100) A value or data field grew larger than allowed" and sends no request. If the same file is also passed to -c, that failed run rewrites the jar with no cookies at all. That is harsher than the advisory's "silently abort parsing", and released 8.22.0 behaves the same with these steps.
I would have liked to report this sooner, before 8.23.0 was out, but I've only managed to finish this now and I still have a lot of other curl CVEs to fix for the Debian package.
Affected version
Reproduced the same way with three builds on Debian forky/sid x86_64:
- curl master 9a6d4ffc1 (2026-10-13), debug build;
- the curl-8_22_0 tag, built from git;
- Debian's curl 8.23.0~rc3-1 package, built from 8.23.0-rc3.
The master build's curl -V:
curl 8.23.0-DEV (x86_64-pc-linux-gnu) libcurl/8.23.0-DEV OpenSSL/3.6.5 zlib/1.3.2 brotli/1.2.0 zstd/1.5.7 libidn2/2.3.8 libssh2/1.11.1 nghttp2/1.70.0 OpenLDAP/2.6.14
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt mqtts pop3 pop3s rtsp scp sftp smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli Debug HSTS HTTP2 HTTPS-proxy IDN IPv6 Largefile libz SSL threadsafe UnixSockets zstd
Steps To Reproduce:
The attached hdrsrv.py is a small HTTP server. It answers any path containing /set with the header given on its command line, and any other path with a plain 200.
python3 hdrsrv.py 8080 srv.log Set-Cookie \
"big=$(python3 -c 'print("v"*4000)'); Max-Age=86400" &
printf '127.0.0.1\tFALSE\t/\tFALSE\t2000000000\tone\t1\n' > jar
printf '127.0.0.1\tFALSE\t/\tFALSE\t2000000000\ttwo\t2\n' >> jar
curl -b jar -c jar "http://127.0.0.1:8080/$(python3 -c 'print("a"*1500)')/set"
# exit code 0; after the header comments, the first cookie line is now
# the 5539-character "big" cookie (cookie_output() writes newest first)
curl -b jar http://127.0.0.1:8080/check
# exit code 100, no request reaches the server; the same on every later run
curl -b jar -c jar http://127.0.0.1:8080/check
# exit code 100 again, and the jar is rewritten with no cookies
Impact
Summary:
Any server the user visits can make every later curl run that reads the cookie file fail, until the user removes the line by hand. With the common -b jar -c jar setup, the next run also erases every stored cookie, for all sites. A new cookie is written first, so the server does control where its line lands. That contradicts the advisory's note that it cannot; a cookie that replaces an existing one keeps its old position. This is the CVE-2026-92386 impact, still reachable after the fix, and in 8.18.0 and later the result is a failed transfer and an emptied jar rather than skipped cookies.