CVE-2026-63128
RMCP: Unauthenticated permanent session-table leak in rmcp Streamable HTTP server transport leads to remote denial-of-service
RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.0.0, the rmcp crate's stateful Streamable HTTP server in crates/rmcp/src/transport/streamable_http_server/tower.rs allows an unauthenticated client to send a well-formed JSON-RPC POST that is not an initialization request, or an initialization request with a mismatched protocol header, causing StreamableHttpService::handle_post to call LocalSessionManager.create_session before validating the message. An early validation failure returns without removing the inserted LocalSessionHandle from LocalSessionManager.sessions, permanently retaining session and channel state for the server process lifetime. Repeated requests can grow the shared session table without bound, degrade legitimate-client latency through lock contention, exhaust memory, and terminate the server. This issue is fixed in version 2.0.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
RMCP: Unauthenticated permanent session-table leak in rmcp Streamable HTTP server transport leads to remote denial-of-service
RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.0.0, the rmcp crate's stateful Streamable HTTP server in crates/rmcp/src/transport/streamable_http_server/tower.rs allows an unauthenticated client to send a well-formed JSON-RPC POST that is not an initialization request, or an initialization request with a mismatched protocol header, causing StreamableHttpService::handle_post to call LocalSessionManager.create_session before validating the message. An early validation failure returns without removing the inserted LocalSessionHandle from LocalSessionManager.sessions, permanently retaining session and channel state for the server process lifetime. Repeated requests can grow the shared session table without bound, degrade legitimate-client latency through lock contention, exhaust memory, and terminate the server. This issue is fixed in version 2.0.0.
- Record
CVE-2026-63128- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-401, CWE-772
- Updated
- 2026-11-02
EUVDEUVD-2026-80823
7.5
RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.0.0, the rmcp crate's stateful Streamable HTTP server in crates/rmcp/src/transport/streamable_http_server/tower.rs allows an unauthenticated client to send a well-formed JSON-RPC POST that is not an initialization request, or an initialization request with a mismatched protocol header, causing StreamableHttpService::handle_post to call LocalSessionManager.create_session before validating the message. An early validation failure returns without removing the inserted LocalSessionHandle from LocalSessionManager.sessions, permanently retaining session and channel state for the server process lifetime. Repeated requests can grow the shared session table without bound, degrade legitimate-client latency through lock contention, exhaust memory, and terminate the server. This issue is fixed in version 2.0.0.
- Record
EUVD-2026-80823- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-9pj6-vhgr-3mwh
7.5
RMCP: Unauthenticated permanent session-table leak in rmcp Streamable HTTP server transport leads to remote denial-of-service
Summary
An unauthenticated remote attacker can leak one entry per HTTP request out of the in-memory session table of LocalSessionManager by sending a well-formed JSON-RPC POST that is not an InitializeRequest. The Streamable HTTP server's handle_post allocates the session before it validates the body, then early-returns on the validation failure without calling close_session. The LocalSessionHandle (and the tokio mpsc channel internals it holds) is never released for the remainder of the process's lifetime — turning a ~250-byte request into a permanent ~400–550-byte server-side allocation that scales linearly with request volume and eventually exhausts memory. In the verified reproduction below, a single Python client sustains over 2 000 leak requests per second; that translates to roughly 170 million leaked entries per day, equivalent to ≈75 GB of resident memory just from the session table.
Details
The bug lives in crates/rmcp/src/transport/streamable_http_server/tower.rs inside StreamableHttpService::handle_post. The relevant slice of 1.7.0 source (lines 1126–1170) is:
} else {
let (session_id, transport) = self
.session_manager
.create_session() // (★)
.await
.map_err(internal_error_response("create session"))?;
// ...capture init params if a SessionStore is configured...
if let ClientJsonRpcMessage::Request(req) = &mut message {
let ClientRequest::InitializeRequest(init_req) = &req.request else {
return Err(unexpected_message_response("initialize request")); // (A)
};
validate_header_matches_init_body( // (B)
&part.headers,
init_req.params.protocol_version.as_str(),
Some(req.id.clone()),
)?;
req.request.extensions_mut().insert(part);
} else {
return Err(unexpected_message_response("initialize request")); // (C)
}
let service = self
.get_service() // (D)
.map_err(internal_error_response("get service"))?;
Self::spawn_session_worker( // (★★)
self.session_manager.clone(),
session_id.clone(),
service,
transport,
None,
);
// ...persist to external store, send response...
}
Two facts make this unsafe:
(★)inserts aLocalSessionHandleintoLocalSessionManager.sessions(atokio::sync::RwLock<HashMap<SessionId, LocalSessionHandle>>) and spawns aLocalSessionWorkertask.(★★)spawn_session_workeris the only code path in the entire transport (besides a client-initiated HTTPDELETEreachinghandle_delete) that ever invokesself.session_manager.close_session(&session_id).
Therefore the four early-returns (A), (B), (C), and (D) all skip the cleanup. What happens concretely after such an early return:
- The local
transport: WorkerTransport<LocalSessionWorker>goes out of scope; its_drop_guardcancels the worker'sCancellationToken. - The worker, which had been awaiting
event_rx.recv(), exits within milliseconds viaWorkerQuitReason::Cancelled. Itsevent_rxreceiver is dropped. LocalSessionHandle.event_tx(theSenderhalf of the same mpsc channel) is still alive because it is owned by the HashMap entry that nothing ever removes. The channel'sInner(sized tochannel_capacity = 16by default) remains pinned in memory.
Because the worker has already exited, the SessionConfig::keep_alive and init_timeout cleanup paths cannot run either — they only fire from inside a running worker. The leak is therefore permanent for the lifetime of the server process and grows unbounded with sustained traffic.
The bug is reachable with zero authentication, the default StreamableHttpServerConfig,…
- Record
GHSA-9pj6-vhgr-3mwh- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-401, CWE-772
- Updated
- 2026-11-02
NVD
7.5
RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.0.0, the rmcp crate's stateful Streamable HTTP server in crates/rmcp/src/transport/streamable_http_server/tower.rs allows an unauthenticated client to send a well-formed JSON-RPC POST that is not an initialization request, or an initialization request with a mismatched protocol header, causing StreamableHttpService::handle_post to call LocalSessionManager.create_session before validating the message. An early validation failure returns without removing the inserted LocalSessionHandle from LocalSessionManager.sessions, permanently retaining session and channel state for the server process lifetime. Repeated requests can grow the shared session table without bound, degrade legitimate-client latency through lock contention, exhaust memory, and terminate the server. This issue is fixed in version 2.0.0.
- Record
CVE-2026-63128- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-401, CWE-772
- Updated
- 2026-11-02
OSV
7.5
RMCP: Unauthenticated permanent session-table leak in rmcp Streamable HTTP server transport leads to remote denial-of-service
RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.0.0, the rmcp crate's stateful Streamable HTTP server in crates/rmcp/src/transport/streamable_http_server/tower.rs allows an unauthenticated client to send a well-formed JSON-RPC POST that is not an initialization request, or an initialization request with a mismatched protocol header, causing StreamableHttpService::handle_post to call LocalSessionManager.create_session before validating the message. An early validation failure returns without removing the inserted LocalSessionHandle from LocalSessionManager.sessions, permanently retaining session and channel state for the server process lifetime. Repeated requests can grow the shared session table without bound, degrade legitimate-client latency through lock contention, exhaust memory, and terminate the server. This issue is fixed in version 2.0.0.
- Record
CVE-2026-63128- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-401, CWE-772
- Updated
- 2026-11-02
OSVGHSA-9pj6-vhgr-3mwh
7.5
RMCP: Unauthenticated permanent session-table leak in rmcp Streamable HTTP server transport leads to remote denial-of-service
Summary
An unauthenticated remote attacker can leak one entry per HTTP request out of the in-memory session table of LocalSessionManager by sending a well-formed JSON-RPC POST that is not an InitializeRequest. The Streamable HTTP server's handle_post allocates the session before it validates the body, then early-returns on the validation failure without calling close_session. The LocalSessionHandle (and the tokio mpsc channel internals it holds) is never released for the remainder of the process's lifetime — turning a ~250-byte request into a permanent ~400–550-byte server-side allocation that scales linearly with request volume and eventually exhausts memory. In the verified reproduction below, a single Python client sustains over 2 000 leak requests per second; that translates to roughly 170 million leaked entries per day, equivalent to ≈75 GB of resident memory just from the session table.
Details
The bug lives in crates/rmcp/src/transport/streamable_http_server/tower.rs inside StreamableHttpService::handle_post. The relevant slice of 1.7.0 source (lines 1126–1170) is:
} else {
let (session_id, transport) = self
.session_manager
.create_session() // (★)
.await
.map_err(internal_error_response("create session"))?;
// ...capture init params if a SessionStore is configured...
if let ClientJsonRpcMessage::Request(req) = &mut message {
let ClientRequest::InitializeRequest(init_req) = &req.request else {
return Err(unexpected_message_response("initialize request")); // (A)
};
validate_header_matches_init_body( // (B)
&part.headers,
init_req.params.protocol_version.as_str(),
Some(req.id.clone()),
)?;
req.request.extensions_mut().insert(part);
} else {
return Err(unexpected_message_response("initialize request")); // (C)
}
let service = self
.get_service() // (D)
.map_err(internal_error_response("get service"))?;
Self::spawn_session_worker( // (★★)
self.session_manager.clone(),
session_id.clone(),
service,
transport,
None,
);
// ...persist to external store, send response...
}
Two facts make this unsafe:
(★)inserts aLocalSessionHandleintoLocalSessionManager.sessions(atokio::sync::RwLock<HashMap<SessionId, LocalSessionHandle>>) and spawns aLocalSessionWorkertask.(★★)spawn_session_workeris the only code path in the entire transport (besides a client-initiated HTTPDELETEreachinghandle_delete) that ever invokesself.session_manager.close_session(&session_id).
Therefore the four early-returns (A), (B), (C), and (D) all skip the cleanup. What happens concretely after such an early return:
- The local
transport: WorkerTransport<LocalSessionWorker>goes out of scope; its_drop_guardcancels the worker'sCancellationToken. - The worker, which had been awaiting
event_rx.recv(), exits within milliseconds viaWorkerQuitReason::Cancelled. Itsevent_rxreceiver is dropped. LocalSessionHandle.event_tx(theSenderhalf of the same mpsc channel) is still alive because it is owned by the HashMap entry that nothing ever removes. The channel'sInner(sized tochannel_capacity = 16by default) remains pinned in memory.
Because the worker has already exited, the SessionConfig::keep_alive and init_timeout cleanup paths cannot run either — they only fire from inside a running worker. The leak is therefore permanent for the lifetime of the server process and grows unbounded with sustained traffic.
The bug is reachable with zero authentication, the default StreamableHttpServerConfig,…
- Record
GHSA-9pj6-vhgr-3mwh- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-400, CWE-401, CWE-772
- Updated
- 2026-11-02
OSVRHSA-2026:80764
8.2
Red Hat Security Advisory: goose security update
- Record
RHSA-2026:80764- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N - Updated
- 2026-11-02
OSVRHSA-2026:80765
8.2
Red Hat Security Advisory: goose security update
- Record
RHSA-2026:80765- CVSS 3.1
- 8.2 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N - Updated
- 2026-11-02
OSVopenSUSE-SU-2026:11849-1 No score
openai-codex-0.155.1-1.1 on GA media
These are all security issues fixed in the openai-codex-0.155.1-1.1 package on the GA media of openSUSE Tumbleweed.
- Record
openSUSE-SU-2026:11849-1- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
rmcpcrates.io |
before 2.0.0 | 2.0.0 |
gooseRed Hat:enterprise_linux:9::extensions From an advisory covering 4 CVEs |
before 0:1.45.0-1.el9_8 | 0:1.45.0-1.el9_8 |
goose-debuginfoRed Hat:enterprise_linux:9::extensions From an advisory covering 4 CVEs |
before 0:1.45.0-1.el9_8 | 0:1.45.0-1.el9_8 |
goose-debugsourceRed Hat:enterprise_linux:9::extensions From an advisory covering 4 CVEs |
before 0:1.45.0-1.el9_8 | 0:1.45.0-1.el9_8 |
gooseRed Hat:enterprise_linux:10.2 From an advisory covering 4 CVEs |
before 0:1.45.0-1.el10_2 | 0:1.45.0-1.el10_2 |
goose-debuginfoRed Hat:enterprise_linux:10.2 From an advisory covering 4 CVEs |
before 0:1.45.0-1.el10_2 | 0:1.45.0-1.el10_2 |
goose-debugsourceRed Hat:enterprise_linux:10.2 From an advisory covering 4 CVEs |
before 0:1.45.0-1.el10_2 | 0:1.45.0-1.el10_2 |
openai-codexopenSUSE:Tumbleweed From an advisory covering 3 CVEs |
before 0.155.1-1.1 | 0.155.1-1.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-63128 is a high vulnerability (CVSS 7.5) in Modelcontextprotocol Rust-sdk, published September 16, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.53%, the 45th percentile. Fixed in rmcp 2.0.0.
References
github.com/modelcontextprotocol/rust-sdk/security/advisories/GHSA-9pj6-vhgr-3mwh
github.com/modelcontextprotocol/rust-sdk/pull/934
github.com/modelcontextprotocol/rust-sdk/commit/dfa7fd6f9309deab60bea230b041be9a3fcda846
github.com/modelcontextprotocol/rust-sdk/releases/tag/rmcp-v2.0.0
nvd.nist.gov/vuln/detail/CVE-2026-63128
github.com/advisories/GHSA-9pj6-vhgr-3mwh
Show 35 moreShow less
github.com/CVEProject/cvelistV5/tree/main/cves/2026/63xxx/CVE-2026-63128.json
github.com/modelcontextprotocol/rust-sdk
access.redhat.com/errata/RHSA-2026:80764
access.redhat.com/security/updates/classification
issues.redhat.com/browse/RHEL-254952
security.access.redhat.com/data/csaf/v2/advisories/2026/rhsa-2026_80764.json
access.redhat.com/security/cve/CVE-2026-63127
bugzilla.redhat.com/show_bug.cgi?id=2535503
cve.org/CVERecord?id=CVE-2026-63127
nvd.nist.gov/vuln/detail/CVE-2026-63127
github.com/modelcontextprotocol/rust-sdk/commit/c1a8b29ff2cc45e7820b900dae42cbb4958089ec
github.com/modelcontextprotocol/rust-sdk/pull/937
github.com/modelcontextprotocol/rust-sdk/security/advisories/GHSA-33f5-2c5q-wgwj
access.redhat.com/security/cve/CVE-2026-63128
bugzilla.redhat.com/show_bug.cgi?id=2535485
cve.org/CVERecord?id=CVE-2026-63128
access.redhat.com/security/cve/CVE-2026-72718
bugzilla.redhat.com/show_bug.cgi?id=2513538
cve.org/CVERecord?id=CVE-2026-72718
nvd.nist.gov/vuln/detail/CVE-2026-72718
github.com/aaif-goose/goose/commit/f8b5b7ba1fe6d006ccf6942f6b85a1bae985a2de
github.com/aaif-goose/goose/releases/tag/v1.44.0
github.com/aaif-goose/goose/security/advisories/GHSA-r5pp-p5r8-466r
access.redhat.com/security/cve/CVE-2026-93599
bugzilla.redhat.com/show_bug.cgi?id=2538431
cve.org/CVERecord?id=CVE-2026-93599
nvd.nist.gov/vuln/detail/CVE-2026-93599
github.com/rustls/webpki/security/advisories/GHSA-82j2-j2ch-gfr8
vulncheck.com/advisories/rustls-webpki-before-0.103.13-panic-via-empty-bit-string
access.redhat.com/errata/RHSA-2026:80765
issues.redhat.com/browse/RHEL-254954
security.access.redhat.com/data/csaf/v2/advisories/2026/rhsa-2026_80765.json
suse.com/security/cve/CVE-2026-63127
suse.com/security/cve/CVE-2026-63128
suse.com/security/cve/CVE-2026-64684
Left out here: the rest of 2 source descriptions. The JSON record has them.