{"id":"CVE-2026-64684","aliases":["EUVD-2026-81266","GHSA-9g45-5xwm-f3wc","openSUSE-SU-2026:11849-1"],"status":"published","title":"RMCP: Custom HTTP headers leak to cross-origin redirect targets","description":"RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.1.0, the rmcp crate's StreamableHttpClientTransport in crates/rmcp/src/transport/common/reqwest/streamable_http_client.rs builds its default_http_client with reqwest's automatic redirect policy and applies caller-supplied values from StreamableHttpClientTransportConfig.custom_headers without marking them as sensitive. When a malicious or compromised MCP endpoint returns a cross-origin 307 or 308 redirect, reqwest follows the redirect and apply_custom_headers causes custom API keys or authentication tokens to be replayed to the new origin, where an attacker can capture and reuse them. The separate auth_header path is not affected because it uses the standard Authorization header, which reqwest strips on cross-origin redirects. This issue is fixed in version 2.1.0.","severity":{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.005,"percentile":0.43119,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-200"],"published":"2026-09-16T21:18:48Z","modified":"2026-10-28T02:30:29Z","fixes":[{"ecosystem":"crates.io","package":"rmcp","fixed_in":["2.1.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"crates.io","package":"rmcp","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.1.0"}]}]},{"source":"osv","ecosystem":"crates.io","package":"rmcp","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.1.0"}]}]},{"source":"osv","ecosystem":"openSUSE:Tumbleweed","package":"openai-codex","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.155.1-1.1"}]}],"bundled":3}],"products":[{"vendor":"modelcontextprotocol","product":"rust-sdk"}],"references":[{"url":"https://github.com/modelcontextprotocol/rust-sdk/security/advisories/GHSA-9g45-5xwm-f3wc","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/modelcontextprotocol/rust-sdk/pull/936","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/modelcontextprotocol/rust-sdk/commit/496902b9cf2c8a947454718da31829ae776b969b","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/modelcontextprotocol/rust-sdk/releases/tag/rmcp-v2.1.0","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-64684","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-9g45-5xwm-f3wc"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/64xxx/CVE-2026-64684.json","tags":["advisory"]},{"url":"https://github.com/modelcontextprotocol/rust-sdk","tags":["package"]},{"url":"","tags":["advisory"]},{"url":"https://www.suse.com/security/cve/CVE-2026-63127","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-63128","tags":["web"]},{"url":"https://www.suse.com/security/cve/CVE-2026-64684","tags":["web"]}],"sources":{"cve":[{"id":"CVE-2026-64684","title":"RMCP: Custom HTTP headers leak to cross-origin redirect targets","description":"RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.1.0, the rmcp crate's StreamableHttpClientTransport in crates/rmcp/src/transport/common/reqwest/streamable_http_client.rs builds its default_http_client with reqwest's automatic redirect policy and applies caller-supplied values from StreamableHttpClientTransportConfig.custom_headers without marking them as sensitive. When a malicious or compromised MCP endpoint returns a cross-origin 307 or 308 redirect, reqwest follows the redirect and apply_custom_headers causes custom API keys or authentication tokens to be replayed to the new origin, where an attacker can capture and reuse them. The separate auth_header path is not affected because it uses the standard Authorization header, which reqwest strips on cross-origin redirects. This issue is fixed in version 2.1.0.","status":"published","published":"2026-09-16T21:18:48.886Z","modified":"2026-09-19T01:56:51.763Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T14:19:58.214427Z"}],"euvd":[{"id":"EUVD-2026-81266","description":"RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.1.0, the rmcp crate's StreamableHttpClientTransport in crates/rmcp/src/transport/common/reqwest/streamable_http_client.rs builds its default_http_client with reqwest's automatic redirect policy and applies caller-supplied values from StreamableHttpClientTransportConfig.custom_headers without marking them as sensitive. When a malicious or compromised MCP endpoint returns a cross-origin 307 or 308 redirect, reqwest follows the redirect and apply_custom_headers causes custom API keys or authentication tokens to be replayed to the new origin, where an attacker can capture and reuse them. The separate auth_header path is not affected because it uses the standard Authorization header, which reqwest strips on cross-origin redirects. This issue is fixed in version 2.1.0.","status":"published","published":"2026-09-16T21:18:48Z","modified":"2026-09-19T01:56:51Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"updated_at":"2026-11-02T17:28:06.992666Z"}],"ghsa":[{"id":"GHSA-9g45-5xwm-f3wc","title":"RMCP: Custom HTTP headers leak to cross-origin redirect targets","description":"## 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() -\u003e 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\u003cHeaderName, HeaderValue\u003e,\n) -\u003e Result\u003creqwest::RequestBuilder, StreamableHttpError\u003creqwest::Error\u003e\u003e {\n    for (name, value) in custom_headers {\n        validate_custom_header(\u0026name).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\u003cHeaderName, HeaderValue\u003e,\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() -\u003e reqwest::Client {\n    reqwest::Client::builder()\n        .pool_max_idle_per_host(0)\n        .redirect(reqwest::redirect::Policy::none())  // \u003c-- 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.","status":"published","published":"2026-09-17T14:48:12Z","modified":"2026-09-17T16:36:37Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T14:41:18.357514Z"}],"nvd":[{"id":"CVE-2026-64684","description":"RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.1.0, the rmcp crate's StreamableHttpClientTransport in crates/rmcp/src/transport/common/reqwest/streamable_http_client.rs builds its default_http_client with reqwest's automatic redirect policy and applies caller-supplied values from StreamableHttpClientTransportConfig.custom_headers without marking them as sensitive. When a malicious or compromised MCP endpoint returns a cross-origin 307 or 308 redirect, reqwest follows the redirect and apply_custom_headers causes custom API keys or authentication tokens to be replayed to the new origin, where an attacker can capture and reuse them. The separate auth_header path is not affected because it uses the standard Authorization header, which reqwest strips on cross-origin redirects. This issue is fixed in version 2.1.0.","status":"published","published":"2026-09-16T22:17:04.577Z","modified":"2026-09-23T18:12:04.247Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T14:12:49.013904Z"}],"osv":[{"id":"CVE-2026-64684","title":"RMCP: Custom HTTP headers leak to cross-origin redirect targets","description":"RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.1.0, the rmcp crate's StreamableHttpClientTransport in crates/rmcp/src/transport/common/reqwest/streamable_http_client.rs builds its default_http_client with reqwest's automatic redirect policy and applies caller-supplied values from StreamableHttpClientTransportConfig.custom_headers without marking them as sensitive. When a malicious or compromised MCP endpoint returns a cross-origin 307 or 308 redirect, reqwest follows the redirect and apply_custom_headers causes custom API keys or authentication tokens to be replayed to the new origin, where an attacker can capture and reuse them. The separate auth_header path is not affected because it uses the standard Authorization header, which reqwest strips on cross-origin redirects. This issue is fixed in version 2.1.0.","status":"published","published":"2026-09-16T21:18:48.886Z","modified":"2026-10-28T02:30:29.647754522Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T15:45:14.096824Z"},{"id":"GHSA-9g45-5xwm-f3wc","title":"RMCP: Custom HTTP headers leak to cross-origin redirect targets","description":"## 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() -\u003e 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\u003cHeaderName, HeaderValue\u003e,\n) -\u003e Result\u003creqwest::RequestBuilder, StreamableHttpError\u003creqwest::Error\u003e\u003e {\n    for (name, value) in custom_headers {\n        validate_custom_header(\u0026name).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\u003cHeaderName, HeaderValue\u003e,\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() -\u003e reqwest::Client {\n    reqwest::Client::builder()\n        .pool_max_idle_per_host(0)\n        .redirect(reqwest::redirect::Policy::none())  // \u003c-- 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.","status":"published","published":"2026-09-17T14:48:12Z","modified":"2026-09-17T16:45:06.215938994Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N","level":"medium"}],"cwes":["CWE-200"],"updated_at":"2026-11-02T15:46:43.875515Z"},{"id":"openSUSE-SU-2026:11849-1","title":"openai-codex-0.155.1-1.1 on GA media","description":"These are all security issues fixed in the openai-codex-0.155.1-1.1 package on the GA media of openSUSE Tumbleweed.","status":"published","published":"2026-09-22T00:00:00Z","modified":"2026-09-23T09:15:05.848245611Z","updated_at":"2026-11-02T16:58:39.516824Z"}]}}
