Heap buffer overread · Squid Proxy · disclosed Jun 2026

squidbleed

A Heartbleed-style vulnerability that leaks internal memory from every version of Squid Proxy in its default configuration. A one-line bug — a quirk of strchr and the null terminator — that survived 29 years of releases, audits and rewrites.

Read the analysis → View PoC on GitHub ↗
attacker@tide:~
$ squid -v
Squid Cache: Version 5.7  [ VULNERABLE ]
$ ./squidbleed --leak
leaked> Authorization: Bearer sk-live_9fX2a
SCROLL
◈ EVERY VERSION AFFECTEDDEFAULT CONFIG · NO FLAGS NEEDED◈ HEAP MEMORY OVERREADFTP DIRECTORY LISTING PARSER◈ 29 YEARS OLD · SINCE 1997strchr(w_space, '\0') ≠ NULL◈ LEAKS VICTIM HTTP REQUESTS ◈ EVERY VERSION AFFECTEDDEFAULT CONFIG · NO FLAGS NEEDED◈ HEAP MEMORY OVERREADFTP DIRECTORY LISTING PARSER◈ 29 YEARS OLD · SINCE 1997strchr(w_space, '\0') ≠ NULL◈ LEAKS VICTIM HTTP REQUESTS
// 00

At a glance

WHAT
Heap buffer overread in Squid's FTP directory-listing parser, leaking adjacent heap memory.
SEVERITY
7.5HIGH · info leak
AFFECTED
Every Squid version in default config. FTP enabled & port 21 in Safe_ports out of the box.
ATTACK VECTOR
Victim browses an attacker-controlled FTP server through the proxy; malformed LIST line triggers the overread.
IMPACT
Other users' cleartext HTTP requests — including Authorization headers, cookies, API keys.
FIX
One-line null check before strchr — or simply disable FTP. Patch available.
// 01

Anatomy of the bug

A 29-year-old footgun in FTP listing parsing

Squid renders a nice HTML page when you browse an FTP directory through it. But FTP has no standardized machine-readable listing format — the LIST command just returns something that loosely resembles ls -l.

In January 1997, a fix taught Squid to handle NetWare FTP servers, which pad four spaces between the timestamp and the filename instead of one. That whitespace-skipping code is still here, nearly 30 years on — and it carries the bug.

It comes down to C's favorite footguns: null-terminated strings, pointer arithmetic, and one weird strchr edge case.

NetWare FTP LIST output · 4-space padding
d [R----F--] supervisor    512  Jan 16 18:53    login
- [R----F--] rhesus    214059  Oct 20 15:27    cx.exe
d [R----F--] supervisor    512  Jan 16 18:53   ← no filename!
src/Ftp/Gateway.cc · htmlifyListEntry() VULNERABLE
// from compat/compat_shared.h
#define w_space " \t\n\r"

copyFrom = buf + tokens[i + 2].pos + strlen(tokens[i + 2].token);
if (flags.skip_whitespace) {
    while (strchr(w_space, *copyFrom))   // ← never stops at '\0'
        ++copyFrom;
} else {
    /* single space between date and filename */
    if (strchr(w_space, *copyFrom))
        ++copyFrom;
}
p->name = xstrdup(copyFrom);   // copies whatever copyFrom now points to
!
THE QUIRK · C11 §7.24.5.2

strchr(w_space, '\0') returns non-NULL — the terminating NUL is considered part of the string. So when a listing line has no filename, *copyFrom is '\0', the loop doesn't stop, ++copyFrom walks straight off the end of the buffer, and xstrdup copies whatever lives next in heap memory.

NORMAL · filename present
..18:53 login \0

Pointer skips the space, lands on l, stops. xstrdup copies "login". Correct.

ATTACK · no filename
..18:53 \0 →→→ Authoriz…

Pointer walks past \0 into adjacent heap. xstrdup copies a stranger's memory.

AddressSanitizer · runtime report
==ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 4065 at 0x6120000d3001 thread T0
  #1 xstrdup
  #2 Ftp::Gateway::htmlifyListEntry
  0 bytes after 4096-byte region [0x...2000,0x...3000)
// 02

The attack flow

How a freed buffer full of someone else's HTTP request finds its way back out through an FTP directory listing. Step through it.

ATTACKER Malicious client + rogue FTP server VICTIM Innocent user cleartext HTTP request SQUID PROXY htmlifyListEntry FTP directory listing parser MEM_4K_BUF pool · not zeroed FTP SERVER · :21 Attacker-owned replies to LIST, no filename HEAP · FREELIST Recycled 4 KB buffer stale victim bytes survive
STEP
{{ ftpNum }} / {{ ftpTotal }}
traffic attack leak
{{ ftpTag }}

{{ ftpTitle }}

{{ ftpDesc }}

// 03

The leak, byte by byte

Squid's pools never zero recycled buffers. A short FTP line overwrites only the first few dozen bytes of a freed 4 KB buffer — the rest is a stranger's HTTP request, and the overread walks right into it. Run the exploit.

MEM_4K_BUF · 4096 bytes 64 × 64
FTP line \0 victim bytes leaked
VICTIM'S RECYCLED REQUEST · still in the bufferidle
┌ overwritten by FTP line ───────────────┐
GET /admin/billing HTTP/1.1
Host: internal.acme.corp
└ leaked from here on ───────────────────┘
Authorization: Bearer sk-live_9fX2aQ7bN4pR8
Cookie: session=8c1f9d22e7a2; role=admin
User-Agent: Mozilla/5.0 (Macintosh) ...
attacker — FTP directory listing received
Index of ftp://evil.example/pub/
Name                Size   Date
// 04

Blast radius

How much is actually exposed, and why a stock install is enough. Figures below are illustrative estimates, not measured telemetry.

WHAT'S LEAKABLE
HTTPS relayed as opaque CONNECT can't leak. Cleartext & TLS-terminating traffic can.
WHY DEFAULT CONFIG IS ENOUGH
Every precondition ships enabled out of the box. No flags, no tuning.
RELEASES SHIPPED WITH SQUIDBLEED
Nine major release families since 1997 — every one carried the bug. Zero patched until 2026.
29years undetected
// 05

A 29-year fuse

JAN 18, 1997 · commit bb97dd37a
The bug is born

A fix teaches ftpget to recognize NetWare servers and skip whitespace before filenames. The whitespace-skipping strchr loop predates all available commit history.

1997 → 2026 · nine release families
Three decades of releases, audits & rewrites

The code is ported, refactored and modernized again and again — the loop survives every pass. The Squid running on a 2026 airplane Wi-Fi network was released nearly a decade ago, and it's affected too.

SQUID 7.x · the leak gets easier
CLIENT_REQ_BUF_SZ meets MEM_4K_BUF

From 7.x, incoming requests are allocated straight from MEM_4K_BUF — the very pool the FTP parser reclaims. On older builds the request still reaches the pool once promoted past 2 KB.

2026 · disclosure
Claude Mythos Preview surfaces Squidbleed

Asked to investigate Squid's FTP state machine, the model flags the strchr(w_space, '\0') quirk almost immediately. Reported responsibly by Califio with Anthropic; assigned CVE-2026-47729 and patched.

// 06

Am I affected & how to fix it

EXPOSURE CHECK
You run Squid as a forward proxy
FTP support is still enabled (default)
Proxy can reach external port 21 (default)
You relay cleartext HTTP or terminate TLS
VULNERABLE
A default install with these conditions leaks heap memory. Patch or disable FTP now.
THE PATCH · one null check
 if (flags.skip_whitespace) {
-    while (strchr(w_space, *copyFrom))
+    while (*copyFrom && strchr(w_space, *copyFrom))
         ++copyFrom;
 } else {
-    if (strchr(w_space, *copyFrom))
+    if (*copyFrom && strchr(w_space, *copyFrom))
         ++copyFrom;
 }
CAN'T PATCH YET? DISABLE FTP · squid.conf
# Refuse FTP through the proxy entirely
acl FTP proto FTP
http_access deny FTP

# …or drop port 21 from the Safe_ports ACL
# and block the proxy's outbound :21 at the firewall
Chromium dropped FTP years ago — most networks see near-zero legitimate FTP. Turning it off removes this attack surface for free.
// 07

Questions

Is this really like Heartbleed?

Conceptually, yes — it's a buffer overread that discloses adjacent memory which may belong to other users. Unlike Heartbleed it's read-bounded by where the heap walk happens to stop, and the impact is more situational, but it can still leak credentials and session data from cleartext traffic.

I only proxy HTTPS. Am I safe?

Largely. HTTPS is relayed as an opaque CONNECT tunnel, so its contents never sit in a leakable buffer. The exposure is to cleartext HTTP and to setups where Squid terminates TLS itself. The FTP egress precondition still applies.

Does the attacker need special configuration on my side?

No. FTP is enabled by default and port 21 is in the default Safe_ports ACL. The attacker only needs an FTP server reachable from your proxy and the ability to make the proxy fetch from it.

What's the CVE, and is it patched?

It's tracked as CVE-2026-47729. A one-line fix — a null check before strchr — is available. If you can't update immediately, disable FTP as shown above.

Who found it?

Califio, using Claude Mythos Preview to investigate Squid's FTP state machine, in partnership with Anthropic. Full write-up and proof-of-concept are linked below.

// 08

Credits & disclosure

RESEARCH

Discovered by Califio with Claude Mythos Preview, in partnership with Anthropic — part of an ongoing effort to make open-source software a little more secure.

Reported responsibly. The model, trained on the C standard reference, treats strchr(w_space, '\0') returning non-NULL as just another fact — and spotted in minutes what survived 29 years of review.

Full technical write-upblog.calif.io Proof of conceptgithub.com/califio @Squidbleedupdates on X @calif_iothe team behind it