Listen to this Post
The vulnerability resides in the HTTP client transport of the mcp/sdk package (version 0.5.0). The transport reads Server‑Sent‑Events (SSE) responses incrementally, fetching up to 4096 bytes per read operation and appending them to an internal string buffer ($this->sseBuffer .= $chunk;). This buffer is designed to accumulate data until a complete SSE event, delimited by two consecutive newline characters ("\n\n"), is received. Only when that delimiter is found does the code extract the event and flush the processed portion from the buffer.
An attacker who controls the SSE response stream (e.g., a malicious MCP server or a man‑in‑the‑middle on an unencrypted connection) can craft a response that streams an arbitrary number of bytes while never including the `”\n\n”` delimiter. In such a scenario, the buffer never drains. Each call to the transport’s `tick()` method invokes processSSEStream(), which reads another 4 KiB chunk and concatenates it to the buffer. The loop that checks for `”\n\n”` (strpos) never matches, so the buffer grows monotonically with every chunk.
Because PHP’s memory limit is finite (commonly 128 MB, 256 MB, or 512 MB in production), a sufficiently large response—a few hundred megabytes—will eventually exhaust the allowed memory. This triggers a fatal “Allowed memory size exhausted” error, crashing the client process. Even if memory_limit is disabled, the operating system’s Out‑Of‑Memory (OOM) killer will terminate the process once system memory is depleted. The crash is reliable and can be triggered by any server endpoint the client connects to via the `HttpTransport` class.
The vulnerable code path is clearly reachable: a client constructs an `HttpTransport` with the server URL and starts the request/response loop. Each iteration calls tick(), which in turn calls processSSEStream(). The unbounded concatenation occurs at line 203 of src/Client/Transport/HttpTransport.php. There is no length guard or timeout, and the only flush mechanism depends entirely on the presence of the delimiter. The impact is a denial‑of‑service against the MCP client—any client using this library is at risk when connecting to untrusted or malicious SSE endpoints.
DailyCVE Form:
Platform: PHP applications using mcp/sdk
Version: v0.5.0
Vulnerability : Unbounded buffer memory exhaustion
Severity: High
date: 2026-08-20 (report date)
Prediction: Patch expected within days
What Undercode Say:
Analytics – Reproduction commands and PoC code:
Install the vulnerable package
$ composer require mcp/sdk:0.5.0 –no-interaction
$ composer show mcp/sdk
PoC driver (poc_sse.php) – negative control (well‑formed events)
$ php poc_sse.php control
[bash] events fed : 1000 well-formed SSE events (delimited by \n\n)
[bash] mem before : 2.0 MB
[bash] mem after : 2.0 MB
[bash] RESULT : bounded, no OOM (each event flushed on \n\n)
Attack – 400 MB body without \n\n (memory_limit set to 256M)
$ php poc_sse.php attack
[bash] SSE body : 400.0 MB with NO \n\n delimiter
[bash] memory_limit : 256M
[bash] mem before : 2.0 MB
PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 264241184 bytes) in /vendor/mcp/sdk/src/Client/Transport/HttpTransport.php on line 203
[bash] peak mem : 256.0 MB
[bash] RESULT : OOM — Allowed memory size …
Core vulnerable snippet (src/Client/Transport/HttpTransport.php)
private function processSSEStream(): void {
if (!$this->activeStream->eof()) {
$chunk = $this->activeStream->read(4096);
if (” !== $chunk) {
$this->sseBuffer .= $chunk; // line 203 – unbounded
}
}
while (false !== ($pos = strpos($this->sseBuffer, “\n\n”))) {
// flush event
}
}
Exploit: (Educational Purposes!)
A remote attacker can crash any MCP client that uses the affected HttpTransport by streaming a large SSE response without ever sending the event delimiter. The PoC above demonstrates this with a FloodStream that returns 400 MB of ‘A’ characters (no “\n\n”) and a memory_limit of 256 MB. The client repeatedly calls pump() (which invokes processSSEStream()) and each call appends another 4 KB to $sseBuffer. The strpos() for “\n\n” never succeeds, the buffer never drains, and the process hits the memory limit, resulting in a fatal error and crash. The same effect can be achieved in a real deployment by a malicious server or a MITM attacker controlling the response body.
Protection: from this CVE
Apply the suggested fix: add a maximum buffer size and abort the stream when exceeded. For example, define a constant (e.g., 8 MiB) and check before appending:
private const MAX_SSE_BUFFER_BYTES = 8 1024 1024;
private function processSSEStream(): void {
if (null === $this->activeStream) return;
if (!$this->activeStream->eof()) {
$chunk = $this->activeStream->read(4096);
if (” !== $chunk) {
if (strlen($this->sseBuffer) + strlen($chunk) > self::MAX_SSE_BUFFER_BYTES) {
$this->sseBuffer = ”;
$this->activeStream = null;
$this->logger->warning(‘Aborting SSE stream: buffer exceeded maximum.’);
return;
}
$this->sseBuffer .= $chunk;
}
}
// … rest of event parsing
}
This bounds memory consumption and prevents unbounded growth. The maintainers should also consider making the limit configurable and logging the abort.
Impact:
- Denial of service (memory exhaustion) leading to process crash.
- Exploitable by any remote MCP server the client connects to, or any party that can inject into the server’s SSE response body (plaintext MITM, compromised server).
- A few hundred MB of delimiter‑free data is sufficient to kill a typical PHP client with a 256 MB memory_limit.
- Affects all versions using the vulnerable transport (v0.5.0; likely earlier versions if they include this code).
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

