{"slug": "squidbleed-cve-2026-47729", "title": "Squidbleed (CVE-2026-47729)", "summary": "A 29-year-old heap buffer overread vulnerability, dubbed Squidbleed (CVE-2026-47729), has been discovered in all versions of Squid Proxy in its default configuration. The bug, found by Anthropic's Claude Mythos Preview, leaks internal memory via FTP directory listing parsing, exposing cleartext HTTP requests. The flaw predates Squid's commit history and affects multi-user environments like schools and corporate networks.", "body_md": "# Squidbleed (CVE-2026-47729)\n\n### Heartbleed's ancient cousin, hiding in Squid since 1997.\n\nTwo weeks ago, we dropped an [HTTP/2 bomb](https://blog.calif.io/p/codex-discovered-a-hidden-http2-bomb) cooked up by Codex Cyber. This time, we sent Claude Mythos Preview spelunking through Squid’s guts, and it surfaced clutching a 29-year-old bug.\n\nMeet **Squidbleed**: a Heartbleed-style vulnerability that leaks internal memory from every version of Squid Proxy, in its default configuration.\n\nThis bug is a whirlwind tour of old-school Internet lore. It involves FTP, NetWare, and DJB, names that only the most diehard Internet fans will recognize.\n\nIt comes down to a few of C's favorite footguns: null-terminated strings, pointer arithmetic, and a weird `strchr`\n\nedge case. Mix these ingredients into an open-source web proxy, and you get a heap buffer overread that quietly leaks random users' HTTP requests, despite three decades of releases, audits, and rewrites.\n\nOne caveat: the impact is situational. Most traffic is HTTPS, which the proxy relays as an opaque `CONNECT`\n\ntunnel, so only cleartext HTTP and TLS-terminating setups are exposed. The proxy must also be allowed to reach an attacker-controlled FTP server (TCP port 21).\n\nA tip of the hat to Anthropic, our partner-in-crime on the quest to make open-source software a little more secure.\n\n## The Target: Squid Proxy\n\nSquid is a widely deployed multipurpose web proxy. While it was designed to speed up page loads by caching frequently accessed content, it can also be used for traffic interception, monitoring, and filtering.\n\nThus, Squid is often found in multi-user environments such as schools or corporate networks. In fact, I encountered Squid while attempting to access the Internet on a recent flight:\n\nAs you might expect, the version of Squid deployed on that plane was released nearly 10 years ago and is affected by the vulnerability I'm about to share with you.\n\n## FTP: Finicky To Parse\n\nWhile HTTP forms the majority of web traffic, Squid also supports FTP (File Transfer Protocol, a legacy protocol for moving files between machines) by default.\n\nWhen connecting to an FTP server via Squid, a nice HTML file listing is helpfully generated:\n\nUnfortunately for Squid, FTP doesn't have a standardized machine-readable file listing format. Instead, the FTP `LIST`\n\ncommand typically returns something that sort of looks like the output from `ls -l`\n\n:\n\n```\n-rw-r--r--    1 1000     1000           40 May 20 04:17 hello.txt\n-rw-r--r--    1 1000     1000           21 May 20 04:17 readme.txt\n```\n\nThis poorly-specified textual format is notoriously hard to parse, especially while staying compatible with every FTP server on the Internet. One of our Internet heroes, DJB, wrote about it too, calling the format [hard to parse with even moderate reliability](https://cr.yp.to/ftp/list.html). And when DJB says something is hard, you know it really is.\n\nIt is thus no surprise that when I asked Claude Mythos Preview to:\n\nSpawn more agents to investigate the full [FTP] state machine behavior better\n\none of the first bugs it found was in Squid's FTP directory listing parser.\n\n## Searching for `NULL`\n\nThe bug predates all available commit history in [Squid's GitHub repo](https://github.com/squid-cache/squid/).\n\nCommit [ bb97dd37a](https://github.com/squid-cache/squid/commit/bb97dd37a), created on Jan 18, 1997, includes the following changelog entry:\n\nFixed ftpget to recognize 'NetWare' servers and skip whitespace before filenames.\n\nNetWare was a network operating system, wildly popular in the late 80s and 90s for running corporate file and print servers, and its bundled FTP service was a common way to move files on and off those machines.\n\nThis was necessary as [NetWare FTP servers output 4 spaces](https://cr.yp.to/ftpparse/ftpparse.c) between the modification timestamp and the filename:\n\n```\nd [R----F--] supervisor            512       Jan 16 18:53    login\n- [R----F--] rhesus             214059       Oct 20 15:27    cx.exe\n```\n\nThis was contrary to the behavior of most other FTP servers, which used just a single space.\n\nWith that historical context in mind, let's have a look at the [modern implementation](https://github.com/squid-cache/squid/blob/dc001f638/src/clients/FtpGateway.cc#L625-L640) of that fix, nearly 30 years on:\n\n```\n// from compat/compat_shared.h\n#define w_space     \" \\t\\n\\r\"\n\ncopyFrom = buf + tokens[i + 2].pos + strlen(tokens[i + 2].token);\nif (flags.skip_whitespace) {\n    while (strchr(w_space, *copyFrom))\n        ++copyFrom;\n} else {\n    /* Handle the following four formats:\n        * \"MMM DD  YYYY Name\"\n        * \"MMM DD  YYYYName\"\n        * \"MMM DD YYYY  Name\"\n        * \"MMM DD YYYY Name\"\n        * Assuming a single space between date and filename\n        * suggested by:  Nathan.Bailey@cc.monash.edu.au and\n        * Mike Battersby <mike@starbug.bofh.asn.au> */\n    if (strchr(w_space, *copyFrom))\n        ++copyFrom;\n}\np->name = xstrdup(copyFrom);\n```\n\nAfter parsing the timestamp, `copyFrom`\n\npoints to the first byte after it. If the FTP server's banner contains \"NetWare\", `flags.skip_whitespace`\n\nis set, and the `while(strchr(w_space, *copyFrom))`\n\nloop skips past the extra whitespace.\n\nOnce `copyFrom`\n\nlands on the first non-whitespace byte, `xstrdup`\n\ncopies it out as the filename. Looks correct, right?\n\nIt seemed like the perfect application of the C pointer arithmetic they teach in school.\n\nBut Claude Mythos Preview thought otherwise.\n\nConfirmed. strchr(w_space, '\\0') returns non-NULL per C11 §7.24.5.2 (terminating NUL is part of the string). This is a real bug.\n\nThe bug occurs when no filename is provided after the modification timestamp. Here's such an example:\n\n```\nd [R----F--] supervisor            512       Jan 16 18:53\n```\n\nIn that case, `*copyFrom`\n\nis the null terminator at the end of the string.\n\nHowever, instead of returning `NULL`\n\nand breaking out of the loop, `strchr`\n\nreturns a pointer to the null terminator, as it is [considered part of the string](https://cppreference.com/c/string/byte/strchr).\n\nThis causes `++copyFrom`\n\nto be executed and the cycle repeats until a non-null, non-whitespace byte is reached.\n\nThis results in a heap overread that is caught by ASAN:\n\n```\nheap-buffer-overflow ... READ of size 4065 ... 0 bytes after 4096-byte region\n  #1 xstrdup\n  #2 Ftp::Gateway::htmlifyListEntry\n```\n\nThe `copyFrom`\n\npointer thus ends up pointing to a byte outside the FTP directory listing buffer.\n\nThe data starting from that byte, possibly belonging to another Squid Proxy user, is then returned to the attacker as the `name`\n\nof a file in the directory listing.\n\nSince FTP support is enabled out of the box, and port 21 is included in the default `Safe_ports`\n\nACL, no special flags or non-default settings are needed. The attacker only needs to control an FTP server reachable from the proxy.\n\n## Bleeding HTTP Headers\n\nNow that we have a heap overread, what can we actually leak?\n\nThe obvious target is HTTP requests, the most common form of web traffic and one that often contains passwords or API keys.\n\nSquid maintains per-size freelists on top of `malloc`\n\n. When a buffer is freed, it is pushed onto the pool's freelist rather than returned to the system allocator. The next allocation of the same type pops from that freelist, and because the pool [does not zero recycled buffers](https://github.com/squid-cache/squid/blob/dc001f638/src/mem/PoolMalloc.cc), the old contents survive intact.\n\nThe `line`\n\nbuffer used to parse FTP listings is [allocated from MEM_4K_BUF](https://github.com/squid-cache/squid/blob/dc001f638/src/clients/FtpGateway.cc#L930). If that buffer previously held a victim's HTTP request, only the first few dozen bytes are overwritten by the short FTP line — the rest of the 4KB buffer still contains the victim's stale data. The\n\n`strchr`\n\noverread walks right past the null terminator and sends it all to the attacker.For this to work, the victim's data must pass through `MEM_4K_BUF`\n\nat some point. On Squid 7.x, that is easy: [ CLIENT_REQ_BUF_SZ is set to 4096](https://github.com/squid-cache/squid/blob/2e58fa81c730/src/defines.h#L86), and is\n\n[allocated with](https://github.com/squid-cache/squid/blob/2e58fa81c730/src/sbuf/MemBlob.cc#L99-L114), which draws from\n\n`memAllocBuf`\n\n`MEM_4K_BUF`\n\n. Therefore, most HTTP requests (except those larger than 4KB) will be stored in a `MEM_4K_BUF`\n\n.However, prior to Squid 7.x, incoming HTTP requests were [allocated using memAllocString](https://github.com/squid-cache/squid/blob/a8c54a8f23f0/src/sbuf/MemBlob.cc#L94), which uses the separate \"4KB Strings\" pool. This is the case on our Debian test setup, as Debian distributes Squid 5.7.\n\nHope is not all lost though, as Squid [copies the outgoing request](https://github.com/squid-cache/squid/blob/5bb2694408e7/src/http.cc#L2452) into a `MemBuf`\n\nbefore forwarding it upstream. While `MEM_2K_BUF`\n\nis used by default, requests exceeding 2KB are promoted to `MEM_4K_BUF`\n\n. Once that buffer is freed, the attacker can reclaim it by spraying FTP directory listing requests.\n\nTo demonstrate the attack, I set up a simple login page for a web app and showed that the `Authorization`\n\nheader can be leaked by an attacker using the same Squid proxy as the victim:\n\nPoCs: [https://github.com/califio/publications/tree/main/MADBugs/squidbleed](https://github.com/califio/publications/tree/main/MADBugs/squidbleed).\n\n## Plugging the Leak\n\n[The patch](https://github.com/squid-cache/squid/commit/865a131c7d557e68c965043d98c2eccae26deef8) is simple: check for the null terminator before calling `strchr`\n\n.\n\n```\n     if (flags.skip_whitespace) {\n-        while (strchr(w_space, *copyFrom))\n+        while (*copyFrom && strchr(w_space, *copyFrom))\n             ++copyFrom;\n     } else {\n         ...\n-        if (strchr(w_space, *copyFrom))\n+        if (*copyFrom && strchr(w_space, *copyFrom))\n             ++copyFrom;\n     }\n```\n\n## Conclusion\n\nThe dangers of raw memory access in C are well understood, but the subtleties of standard library functions like `strchr`\n\nare easier to overlook. Few developers would guess that searching for `'\\0'`\n\nsucceeds, which may explain how a one-line bug survived close to 30 years of code review.\n\nClaude Mythos Preview, having trained on the entire C standard reference, treats this quirk as just another fact. When pointed at the right code, it spotted the bug almost immediately.\n\nAs a mitigation, you really ought to disable FTP at this point unless you have a specific, unusual need for it. Chrome, and by extension all Chromium-based browsers, dropped FTP support years ago, so most organizations running Squid are getting close to zero legitimate FTP traffic. Turning it off removes this entire attack surface for free.\n\nMore broadly, this might be a good habit for OSS maintainers in general: every now and then, ask an LLM which features you can safely drop. Dead code that nobody uses is still code that can be exploited.\n\nThough FTP parsing might not be the only place where Squid forgot to stop reading. Stay tuned for the next round.\n\n## Disclosure Timeline\n\n2026-04-17: Initial report by Lam Jun Rong of Calif.io\n\n2026-04-17: Fix posted\n\n2026-04-19: Fix merged into master/v8\n\n2026-05-07: Independent report by Youssef Awad\n\n2026-05-17: Fix merged into v7\n\n2026-06-08: Squid v7.6 released\n\n2026-06-10: This blog post released", "url": "https://wpnews.pro/news/squidbleed-cve-2026-47729", "canonical_source": "https://blog.calif.io/p/squidbleed-cve-2026-47729", "published_at": "2026-06-18 19:35:22+00:00", "updated_at": "2026-06-18 20:06:30.200096+00:00", "lang": "en", "topics": ["ai-safety", "ai-research"], "entities": ["Squid", "Anthropic", "Claude Mythos Preview", "Codex Cyber", "NetWare", "DJB", "CVE-2026-47729"], "alternates": {"html": "https://wpnews.pro/news/squidbleed-cve-2026-47729", "markdown": "https://wpnews.pro/news/squidbleed-cve-2026-47729.md", "text": "https://wpnews.pro/news/squidbleed-cve-2026-47729.txt", "jsonld": "https://wpnews.pro/news/squidbleed-cve-2026-47729.jsonld"}}