Background
The Streamable HTTP server transport currently validates only the Host header for DNS rebinding protection (added in #764, shipped in v1.4.0, tracked in #815). The TypeScript, Python, Go, and Java SDK security advisories for the same class of vulnerability all validate bothHostandOrigin, and the MCP transport security note calls out both headers.
Host-only validation is sufficient to block the specific DNS rebinding attack Jonathan Leitschuh reported (the browser cannot forge the Host header after rebinding). However, Origin validation adds defense-in-depth against a separate misconfiguration class: an operator who binds to 0.0.0.0, disables the host allowlist, and serves permissive CORS (Access-Control-Allow-Origin: *). In that setup, a public malicious page could make same-host cross-site requests that pass the Host check but originate from an untrusted origin.
This is not part of the #815 advisory because it is a separate hardening, not a fix for the reported DNS rebinding issue.
Proposal
Extend StreamableHttpServerConfig with an allowed_origins: Vec<String> field, paralleling allowed_hosts:
- Default: empty → Origin header is not required or validated (preserves current behavior for non-browser clients like the CLI and stdio-bridge test suite that don't send Origin).
- When non-empty: requests carrying an
Origin header must match the allowlist, or are rejected with HTTP 403. Requests without an Origin header are allowed (non-browser clients). - Builder methods:
with_allowed_origins(&[&str]), disable_allowed_origins(). - Reuse the
parse_allowed_authority / host_is_allowed pattern from tower.rs:195-210.
Acceptance Criteria
Related
Background
The Streamable HTTP server transport currently validates only the
Hostheader for DNS rebinding protection (added in #764, shipped in v1.4.0, tracked in #815). The TypeScript, Python, Go, and Java SDK security advisories for the same class of vulnerability all validate bothHostandOrigin, and the MCP transport security note calls out both headers.Host-only validation is sufficient to block the specific DNS rebinding attack Jonathan Leitschuh reported (the browser cannot forge the Host header after rebinding). However,Originvalidation adds defense-in-depth against a separate misconfiguration class: an operator who binds to0.0.0.0, disables the host allowlist, and serves permissive CORS (Access-Control-Allow-Origin: *). In that setup, a public malicious page could make same-host cross-site requests that pass the Host check but originate from an untrusted origin.This is not part of the #815 advisory because it is a separate hardening, not a fix for the reported DNS rebinding issue.
Proposal
Extend
StreamableHttpServerConfigwith anallowed_origins: Vec<String>field, parallelingallowed_hosts:Originheader must match the allowlist, or are rejected with HTTP 403. Requests without anOriginheader are allowed (non-browser clients).with_allowed_origins(&[&str]),disable_allowed_origins().parse_allowed_authority/host_is_allowedpattern from tower.rs:195-210.Acceptance Criteria
validate_dns_rebinding_headerschecks Origin whenallowed_originsis non-empty.crates/rmcp/tests/test_custom_headers.rs:require_origin = true(if we add that knob) → 403StreamableHttpServerConfigrustdoc to describe the recommended production configuration (allowlist both Host and Origin when serving browser clients).Related