CVE-2026-64684: RMCP Custom HTTP Headers Leak To Vulnerability

MODERATE
Advisory Identifier: GHSA-9g45-5xwm-f3wc
CVSS 6.8
CWE-200
Published
Advisory Summary

CVE-2026-64684 is a MODERATE (CVSS 6.8) custom http headers leak to vulnerability (CWE-200: Exposure of Sensitive Information to an Unauthorized Actor) affecting RMCP libraries in the crates.io ecosystem. The issue involves custom http headers leak to cross-origin redirect targets. Remediation is available by upgrading affected packages to version 2.1.0.

CVE-2026-64684 at a Glance

CVE Identifier CVE-2026-64684
GHSA Identifier GHSA-9g45-5xwm-f3wc
Severity MODERATE
CVSS v3.1 Base Score 6.8
CWE Classification CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
Affected Product RMCP
Package Ecosystem crates.io
Published Date
Last Updated

Security Impact

CVSS: 6.8

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity None (I:N)
Availability None (A:N)

How to Fix CVE-2026-64684

To remediate this vulnerability, upgrade all affected RMCP dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

rmcp fixed: 2.1.0
Upgrade rmcp to 2.1.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for rmcp

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-64684, inspect your project dependencies for RMCP:

inspect dependencies for rmcp

Analyze the terminal output to locate any version of RMCP in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.1.0), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor, where the product exposes sensitive information to an actor that is not explicitly authorized to have access to that information. In RMCP, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary The `rmcp` crate's `StreamableHttpClientTransport` forwards caller-supplied custom HTTP headers (such as `X-API-Key`, `X-Auth-Token`, `Api-Key`) to cross-origin redirect targets. The `default_http_client()` function builds a `reqwest::Client` without a redirect policy override, so the default `limited(10)` policy follows `307`/`308` redirects and forwards all per-request headers except `Authorization`, `Cookie`, and `Proxy-Authorization`. Custom auth headers injected via `StreamableHttpClientTransportConfig.custom_headers` are not classified as sensitive and are therefore forwarded verbatim to any redirect target — including an attacker-controlled server. ## Affected versions - Repository: `github.com/modelcontextprotocol/rust-sdk` - Crate: `rmcp` - Commit tested: `c330fede90e4729c234f8e87fdbc5ea27a1dd10c` (HEAD, 2026-05-21) ## Vulnerability **File:** `crates/rmcp/src/transport/common/reqwest/streamable_http_client.rs` **Root cause 1 — no redirect policy override:** ```rust // Lines 302-307 fn default_http_client() -> reqwest::Client { reqwest::Client::builder() .pool_max_idle_per_host(0) .build() .expect("failed to build default reqwest client") } ``` No `.redirect(reqwest::redirect::Policy::none())` call. The default `limited(10)` policy follows up to 10 redirects and, on cross-origin redirects, strips only `Authorization`, `Cookie`, and `Proxy-Authorization`. **Root cause 2 — custom headers not sensitivity-marked:** ```rust // Lines 26-35 fn apply_custom_headers( mut builder: reqwest::RequestBuilder, custom_headers: HashMap<HeaderName, HeaderValue>, ) -> Result<reqwest::RequestBuilder, StreamableHttpError<reqwest::Error>> { for (name, value) in custom_headers { validate_custom_header(&name).map_err(StreamableHttpError::ReservedHeaderConflict)?; builder = builder.header(name, value); // no sensitivity marker } Ok(builder) } ``` Headers added via `RequestBuilder::header()` are forwarded to redirect targets because reqwest only strips headers from its own sensitive-header list (`Authorization`, `Cookie`, `Proxy-Authorization`). **Exposed API:** `StreamableHttpClientTransportConfig.custom_headers` (line 1070), intended for custom auth headers: ```rust /// Custom HTTP headers to include with every request pub custom_headers: HashMap<HeaderName, HeaderValue>, ``` ## Attack scenario 1. A caller sets `custom_headers` with an API key for the MCP server: ```rust let config = StreamableHttpClientTransportConfig::with_uri("https://mcp.example.com/mcp") .custom_headers([(HeaderName::from_static("x-api-key"), HeaderValue::from_static("my-secret-key"))].into()); ``` 2. An attacker compromises `mcp.example.com` to return `307 Temporary Redirect` to `https://attacker.example.net/capture`. 3. `rmcp` follows the redirect, forwarding `X-API-Key: my-secret-key` to `attacker.example.net`. 4. The attacker captures the secret and reuses it to call the MCP server directly. ## Negative control The `auth_header` path (`StreamableHttpClientTransportConfig::auth_header()`) sets the value via `builder.bearer_auth(auth_header)`, which maps to the `Authorization` header — stripped by reqwest on cross-origin redirects. That path is not affected. Only `custom_headers` is vulnerable. ## Fix In `default_http_client()`, disable automatic redirect following: ```rust fn default_http_client() -> reqwest::Client { reqwest::Client::builder() .pool_max_idle_per_host(0) .redirect(reqwest::redirect::Policy::none()) // <-- add this .build() .expect("failed to build default reqwest client") } ``` The transport can then inspect `3xx` responses and decide whether to follow, stripping sensitive headers before doing so. Alternatively, use `reqwest::ClientBuilder::connection_verbose` or per-request `Request::headers_mut()` to remove auth headers before the redirect is followed.

CVE-2026-64684 Affected RMCP Versions

1 component(s)
Fixed Versions:
2.1.0
Product / Package Ecosystem Affected Versions Fixed Version
rmcp
crates.io
< 2.1.0
2.1.0

References

Frequently Asked Questions

What is CVE-2026-64684?
CVE-2026-64684 is a security vulnerability in RMCP involving Custom HTTP headers leak to cross-origin redirect targets under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor.
Which RMCP versions are affected?
Affected versions include releases prior to 2.1.0 across affected packages: rmcp.
What version fixes CVE-2026-64684?
Upgrading to 2.1.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is rmcp affected?
Yes, rmcp is affected in releases prior to 2.1.0. Upgrade your dependency to 2.1.0 or later.
What is the CVSS score of CVE-2026-64684?
CVE-2026-64684 has a CVSS v3.1 base score of 6.8 (MODERATE) with vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N.
What CWE is associated with CVE-2026-64684?
CVE-2026-64684 is classified under CWE-200: Exposure of Sensitive Information to an Unauthorized Actor (The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.).
How can I check crates.io dependencies for CVE-2026-64684?
Run the dependency tree command: 'inspect dependencies for rmcp'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-9g45-5xwm-f3wc",
  "modified" : "2026-09-17T16:36:36Z",
  "published" : "2026-09-17T14:48:12Z",
  "aliases" : [ "CVE-2026-64684" ],
  "summary" : "RMCP: Custom HTTP headers leak to cross-origin redirect targets",
  "details" : "## Summary\n\nThe `rmcp` crate's `StreamableHttpClientTransport` forwards caller-supplied custom HTTP headers (such as `X-API-Key`, `X-Auth-Token`, `Api-Key`) to cross-origin redirect targets. The `default_http_client()` function builds a `reqwest::Client` without a redirect policy override, so the default `limited(10)` policy follows `307`/`308` redirects and forwards all per-request headers except `Authorization`, `Cookie`, and `Proxy-Authorization`. Custom auth headers injected via `StreamableHttpClientTransportConfig.custom_headers` are not classified as sensitive and are therefore forwarded verbatim to any redirect target — including an attacker-controlled server.\n\n## Affected versions\n\n- Repository: `github.com/modelcontextprotocol/rust-sdk`\n- Crate: `rmcp`\n- Commit tested: `c330fede90e4729c234f8e87fdbc5ea27a1dd10c` (HEAD, 2026-05-21)\n\n## Vulnerability\n\n**File:** `crates/rmcp/src/transport/common/reqwest/streamable_http_client.rs`\n\n**Root cause 1 — no redirect policy override:**\n\n```rust\n// Lines 302-307\nfn default_http_client() -> reqwest::Client {\n    reqwest::Client::builder()\n        .pool_max_idle_per_host(0)\n        .build()\n        .expect(\"failed to build default reqwest client\")\n}\n```\n\nNo `.redirect(reqwest::redirect::Policy::none())` call. The default `limited(10)` policy follows up to 10 redirects and, on cross-origin redirects, strips only `Authorization`, `Cookie`, and `Proxy-Authorization`.\n\n**Root cause 2 — custom headers not sensitivity-marked:**\n\n```rust\n// Lines 26-35\nfn apply_custom_headers(\n    mut builder: reqwest::RequestBuilder,\n    custom_headers: HashMap<HeaderName, HeaderValue>,\n) -> Result<reqwest::RequestBuilder, StreamableHttpError<reqwest::Error>> {\n    for (name, value) in custom_headers {\n        validate_custom_header(&name).map_err(StreamableHttpError::ReservedHeaderConflict)?;\n        builder = builder.header(name, value);  // no sensitivity marker\n    }\n    Ok(builder)\n}\n```\n\nHeaders added via `RequestBuilder::header()` are forwarded to redirect targets because reqwest only strips headers from its own sensitive-header list (`Authorization`, `Cookie`, `Proxy-Authorization`).\n\n**Exposed API:** `StreamableHttpClientTransportConfig.custom_headers` (line 1070), intended for custom auth headers:\n\n```rust\n/// Custom HTTP headers to include with every request\npub custom_headers: HashMap<HeaderName, HeaderValue>,\n```\n\n## Attack scenario\n\n1. A caller sets `custom_headers` with an API key for the MCP server:\n   ```rust\n   let config = StreamableHttpClientTransportConfig::with_uri(\"https://mcp.example.com/mcp\")\n       .custom_headers([(HeaderName::from_static(\"x-api-key\"),\n                         HeaderValue::from_static(\"my-secret-key\"))].into());\n   ```\n2. An attacker compromises `mcp.example.com` to return `307 Temporary Redirect` to `https://attacker.example.net/capture`.\n3. `rmcp` follows the redirect, forwarding `X-API-Key: my-secret-key` to `attacker.example.net`.\n4. The attacker captures the secret and reuses it to call the MCP server directly.\n\n## Negative control\n\nThe `auth_header` path (`StreamableHttpClientTransportConfig::auth_header()`) sets the value via `builder.bearer_auth(auth_header)`, which maps to the `Authorization` header — stripped by reqwest on cross-origin redirects. That path is not affected. Only `custom_headers` is vulnerable.\n\n## Fix\n\nIn `default_http_client()`, disable automatic redirect following:\n\n```rust\nfn default_http_client() -> reqwest::Client {\n    reqwest::Client::builder()\n        .pool_max_idle_per_host(0)\n        .redirect(reqwest::redirect::Policy::none())  // <-- add this\n        .build()\n        .expect(\"failed to build default reqwest client\")\n}\n```\n\nThe transport can then inspect `3xx` responses and decide whether to follow, stripping sensitive headers before doing so. Alternatively, use `reqwest::ClientBuilder::connection_verbose` or per-request `Request::headers_mut()` to remove auth headers before the redirect is followed.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "crates.io",
      "name" : "rmcp"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.1.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/modelcontextprotocol/rust-sdk/security/advisories/GHSA-9g45-5xwm-f3wc"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-64684"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/modelcontextprotocol/rust-sdk/pull/936"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/modelcontextprotocol/rust-sdk/commit/496902b9cf2c8a947454718da31829ae776b969b"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/modelcontextprotocol/rust-sdk"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/modelcontextprotocol/rust-sdk/releases/tag/rmcp-v2.1.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-200" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-17T14:48:12Z",
    "nvd_published_at" : "2026-09-16T22:17:04Z"
  }
}