A 29-year-old strchr() edge case that turns the world's most-deployed open-source proxy into a credential photocopier
CVE-2026-47729, dubbed Squidbleed by Lam Jun Rong at Calif.io, is a heap over-read in Squid's FTP directory-listing parser. When the proxy parses a malformed FTP response missing a filename, strchr(w_space, '\0') returns a pointer to the NUL terminator (legal per C11 §7.24.5.2), advancing copyFrom past the 4 KB MEM_4K_BUF boundary. Because Squid recycles those buffers without zeroing, the over-read leaks whatever previously lived in that slab — typically other users' HTTP requests, Authorization headers, cookies, and POST bodies. Every Squid release since 1997 is affected in the default configuration; the fix landed in Squid 7.6 (8 June 2026), backported to v7 on 17 May 2026 and merged into master/v8 on 19 April 2026. Distro packages (SUSE, Debian, RHEL, Ubuntu) are still rolling.
Vendor severity is uneven: there is no NVD/MITRE CVSS yet; SUSE rates it CVSS 6.5 (AV:N/AC:L/PR:L/UI:N/C:H/I:N/A:N) as a *moderate* information disclosure. That under-prices the real-world blast radius. The PR:L assumption presumes the attacker needs proxy auth, but in most enterprise forward-proxy and almost every CDN/reverse-proxy deployment the FTP fetch is triggered by *any* downstream client (including the attacker as a downstream consumer of the same proxy). The leaked bytes are cross-*user*, cross-*tenant* secrets. Calling this a 6.5 is the same mistake the industry made the morning of Heartbleed.
5 steps from start to impact.
Stand up a malicious FTP server
LIST response whose lines omit the filename field after the timestamp. Calif.io's published PoC (github.com/califio/publications/tree/main/MADBugs/squidbleed) ships a 60-line Python listener that does exactly this. No exotic protocol work required.- Internet-routable host or attacker-controlled host reachable from the target Squid instance
- TCP/21 open outbound from the proxy (Squid's default
Safe_portsACL includes 21)
- Egress firewalls that block outbound FTP from proxy tier (uncommon — most Squid deployments allow it by default)
ftp.log will show the proxy initiating outbound FTP control sessions to unusual destinations.Coerce Squid to fetch ftp://attacker/
GET ftp://attacker.tld/ HTTP/1.1. Squid's FTP gateway opens a control connection, issues LIST, and feeds the malformed response into parseListing(). The strchr(w_space, *copyFrom) walk runs off the end of the line buffer.- Attacker can submit requests through the proxy — trivial for reverse-proxy/CDN deployments; requires proxy access (often anonymous on internal networks) for forward proxies
- FTP scheme handling enabled (default on every Squid build)
- Proxies with
acl Safe_ports port 21removed (rare hardening) - SSL-bumping proxies that reject non-HTTP schemes at the front door
access.log records the ftp:// URL but nothing flags the malformed response.Heap over-read leaks recycled buffer contents
MEM_4K_BUF is a 4 KB slab freelist that Squid does *not* zero on free. The short FTP line overwrites only the first ~30 bytes; the remaining ~4060 bytes still contain whatever the buffer last held — almost always a prior victim's HTTP request line, headers, cookies, or Authorization: Basic/Bearer …. The over-read returns those bytes to the attacker as part of the FTP→HTML index page that Squid generates.- Concurrent or recent legitimate HTTP traffic through the same Squid worker (the more traffic, the more leakage)
- Squid's slab allocator (the default since forever)
- Workers with very low concurrent traffic may leak only stale kernel/heap junk
- If victim traffic is HTTPS over CONNECT, the proxy sees only opaque ciphertext and there is nothing useful to leak
Repeat-and-harvest
MEM_4K_BUF slot, exfiltrating a fresh ~4 KB window of memory. Over hours, the attacker reconstructs cleartext HTTP traffic, session cookies, Basic-auth credentials, and JWTs belonging to other users sharing the proxy.- Persistent reachability to the proxy
- Sustained victim traffic volume
- Rate limits on outbound FTP from the proxy (rare)
- Short-lived bearer tokens narrow the window of usable credentials
Credential replay / session hijack
Authorization headers and cookies are replayed against the upstream origin services. For TLS-terminating forward proxies this exposes the internal workforce's SaaS sessions; for CDN/reverse-proxy deployments it exposes *cross-tenant* customer credentials.- Origin services do not bind sessions to client IP/device fingerprint
- Credentials harvested before rotation
- mTLS or device-bound tokens (DPoP, token-binding) neutralize replay
- Short-TTL access tokens with refresh-token rotation limit value
The supporting signals.
| In-the-wild status | No confirmed exploitation as of 21 June 2026. Not on CISA KEV. GreyNoise has no tagged scanner traffic for the FTP-listing signature yet. |
|---|---|
| Proof of concept | Public, working PoC at github.com/califio/publications/tree/main/MADBugs/squidbleed — leaks Authorization headers in the researcher's demo video. |
| EPSS | Not yet scored by FIRST (CVE published <30 days; insufficient data). Expect mid-range once first-pass model runs. |
| KEV status | Not listed. Likely candidate if cross-tenant credential theft is publicly demonstrated against a CDN. |
| CVSS | No NVD score. SUSE assigned 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N — noisgate considers PR:L debatable; the attacker is functionally unauthenticated against any open or anonymous proxy. |
| Affected versions | Every Squid release from 1997 through 7.5 in default configuration. Includes all current LTS lines and every distro package not yet rebuilt. |
| Fixed versions | Squid 7.6 (8 June 2026). Backports pending in Debian, Ubuntu, RHEL/EPEL, SUSE (status *Pending* as of fetch), Alpine. |
| Exposure data | Shodan: ~180k internet-facing Squid/ banner hits; Censys ~210k. The reverse-proxy / CDN edge population is the dangerous slice (cross-tenant blast radius). Forward-proxy population on internal networks is unmeasurable but very large. |
| Disclosure | Reported 2026-04-17 by Lam Jun Rong (Calif.io); coordinated disclosure with Squid maintainers; public writeup *Squidbleed* published alongside Squid 7.6. |
| Class | CWE-126 Buffer Over-read (Heartbleed-class). C11 strchr corner case + non-zeroing slab allocator. |
noisgate verdict.
Role multiplier drives this: Squid is the canonical reverse-proxy/CDN edge and TLS-terminating corporate forward proxy, and in those roles the over-read leaks *cross-user* credentials and session cookies — a fleet- or tenant-scale confidentiality breach, not a single-host info-leak. The decisive factor is blast radius across the multi-tenant role, not exploit difficulty (which is trivial: one FTP server and one HTTP request).
Why this verdict
- Heartbleed-class primitive, public PoC, zero auth in practice — the attacker only needs the proxy to fetch
ftp://attacker/, which any downstream client (including the attacker themselves on most reverse-proxy edges) can trigger. SUSE'sPR:Lassumption does not hold in CDN or anonymous-forward deployments. - Role multiplier — reverse-proxy / CDN edge: chain succeeds; blast radius is *cross-tenant* HTTP request + cookie + Authorization header disclosure. This is the canonical Squid-as-edge deployment and pushes the floor to HIGH.
- Role multiplier — TLS-terminating corporate forward proxy (SSL bump): chain succeeds; blast radius is workforce-wide SaaS credential and session-cookie theft from anyone whose decrypted traffic passes through the proxy. Common in regulated enterprises that do egress inspection.
- Role multiplier — pure CONNECT forward proxy (no TLS termination): chain still triggers, but leaked bytes are mostly TLS ciphertext and a small population of cleartext-HTTP browsing — narrower but non-zero impact. This is the only role that argues *against* HIGH.
- Friction discount applied: worker concurrency and HTTPS-dominant traffic mean each over-read returns a probabilistic slice of useful data, not deterministic credentials — this is why we sit at 7.6 rather than 8.5+.
- Not on KEV, no observed exploitation yet — keeps us under CRITICAL. If credential-replay attacks surface, expect rapid KEV addition and upgrade.
Why not higher?
No active exploitation and no deterministic single-shot credential extraction (the leak is probabilistic across a 4 KB window). Pure CONNECT-only forward proxies — a non-trivial share of installs — leak mostly ciphertext. CRITICAL would require demonstrated cross-tenant compromise in the wild or a deterministic credential primitive.
Why not lower?
SUSE's 6.5 / MEDIUM under-prices the cross-user, cross-tenant nature of the leak and presumes proxy authentication that most real deployments don't enforce against arbitrary FTP URLs. Every Squid build since 1997 is affected, a public PoC leaks Authorization headers, and the canonical Squid roles are *exactly* the multi-tenant ones where the blast radius is largest. Calling this MEDIUM ignores the role-multiplier rule.
What to do — in priority order.
- Disable the FTP scheme handler in
squid.conf— Addacl FTP proto FTPandhttp_access deny FTP(or remove port 21 fromSafe_portsand rejectftp://URLs at the front door). This severs step 2 of the chain — the parser never runs. Deploy within 30 days per the noisgate HIGH mitigation SLA; do it today on internet-facing reverse proxies. - Block outbound TCP/21 from the proxy tier at the egress firewall — Defense-in-depth in case someone re-enables FTP in
squid.conf. Most modern enterprise egress already denies FTP; verify rather than assume. Same 30-day noisgate HIGH mitigation deadline; minutes of firewall work. - Restart Squid workers on a short cadence until patched — Rolling worker restarts (e.g.,
squid -k reconfigurehourly, or systemd timer) flush the recycledMEM_4K_BUFslabs and shorten the leak window. Crude but cheap and immediate while you wait for the distro backport. - Upgrade to Squid 7.6 (or apply distro backport when available) — The actual fix. Track Debian/Ubuntu/RHEL/SUSE security trackers; for self-built Squid pull v7.6 today. Complete the upgrade within the noisgate HIGH 180-day remediation SLA — sooner on internet-facing edges.
- Rotate any Basic-auth and bearer tokens that may have traversed a TLS-terminating Squid since April 2026 — Assume disclosure on multi-tenant CDN and SSL-bumping forward proxies. Force re-auth, invalidate long-lived API tokens, and rotate service-account credentials whose traffic was proxied.
- Patching only the public-facing Squid instances — internal forward proxies with SSL bump leak workforce SaaS credentials and are usually the bigger problem.
- Web Application Firewalls in front of Squid — they inspect HTTP, not the proxy's outbound FTP control channel where the malformed response arrives.
- Disabling anonymous proxy access — does not help on CDN/reverse-proxy deployments where the attacker is a normal downstream client by design.
- TLS 1.3 / HSTS / cert pinning — irrelevant; the leak is in Squid's own heap, not in transport.
- EDR on the proxy host — the over-read is in-process memory access against memory the process legitimately owns; no syscall signature to catch.
Crowdsourced verification payload.
Run on each Squid host as root (or any user that can read squid.conf and run squid -v). Invoke as sudo ./check-squidbleed.sh — the script reports VULNERABLE, PATCHED, or UNKNOWN and exits 1, 0, or 2 respectively. Also flags whether FTP is reachable in the Safe_ports ACL.
#!/usr/bin/env bash
# noisgate verification: CVE-2026-47729 "Squidbleed"
# Detects Squid version and FTP-scheme exposure.
set -u
SQUID_BIN="$(command -v squid || true)"
CONF="${SQUID_CONF:-/etc/squid/squid.conf}"
[ -f "$CONF" ] || CONF="/etc/squid3/squid.conf"
if [ -z "$SQUID_BIN" ]; then
echo "UNKNOWN: squid binary not found in PATH"; exit 2
fi
VER=$("$SQUID_BIN" -v 2>/dev/null | awk -F'Version ' '/Version/ {print $2}' | awk '{print $1}')
if [ -z "$VER" ]; then
echo "UNKNOWN: could not parse Squid version"; exit 2
fi
# Fixed in 7.6+; distros may carry backported patches in earlier strings.
ver_ge() { printf '%s\n%s\n' "$2" "$1" | sort -V -C; }
FTP_EXPOSED="unknown"
if [ -r "$CONF" ]; then
if grep -Eq '^\s*acl\s+Safe_ports\s+port\s+.*\b21\b' "$CONF" && \
! grep -Eq '^\s*http_access\s+deny\s+.*(FTP|ftp)' "$CONF"; then
FTP_EXPOSED="yes"
else
FTP_EXPOSED="no"
fi
fi
if ver_ge "$VER" "7.6"; then
echo "PATCHED: Squid $VER (>=7.6) — FTP-scheme reachable=$FTP_EXPOSED"
exit 0
fi
# Check for distro backport hint in changelog (best-effort)
if command -v dpkg >/dev/null 2>&1; then
CHG=$(dpkg -s squid 2>/dev/null | awk '/^Version:/ {print $2}')
if echo "$CHG" | grep -Eqi 'CVE-2026-47729|squidbleed'; then
echo "PATCHED: distro backport detected ($CHG)"; exit 0
fi
fi
if [ "$FTP_EXPOSED" = "no" ]; then
echo "VULNERABLE-BUT-MITIGATED: Squid $VER, FTP scheme blocked in config"
exit 1
fi
echo "VULNERABLE: Squid $VER < 7.6, FTP-scheme reachable=$FTP_EXPOSED"
exit 1
If you remember one thing.
squid.conf and block outbound TCP/21 from the proxy tier on every Squid host — internet-facing reverse proxies and SSL-bumping forward proxies first. That single config change kills the attack chain and satisfies the noisgate mitigation SLA of ≤ 30 days for a HIGH; do internet-facing edges within 72 hours regardless. Then track Squid 7.6 / distro backports and complete the upgrade within the noisgate remediation SLA of ≤ 180 days. Rotate any Basic-auth credentials and long-lived bearer tokens that have traversed a TLS-terminating Squid since the April 2026 disclosure — assume exposure. If CISA adds this to KEV (likely once cross-tenant exploitation is demonstrated), collapse both timelines to *hours*.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.