Skip to content

Accept every Origin with allowed_origins: :any and keep the Host check - #685

Open
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:accept_every_origin_with_allowed_origins_any_and_keep_the_host_check
Open

koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:accept_every_origin_with_allowed_origins_any_and_keep_the_host_check

Conversation

@koic

@koic koic commented Nov 14, 2026

Copy link
Copy Markdown
Member

Motivation and Context

StreamableHTTPTransport accepts a cross-origin request only when its Origin is listed in allowed_origins:. A remote server that browser-based clients on any origin may call, authenticated by a bearer token alone, had two ways to admit them: dns_rebinding_protection: false, which also turns off the Host check, or building the transport per request with that request's own Origin in the list.

allowed_origins: :any now skips the Origin check alone. A rebound request names the attacker's host in Host and, if sent, Origin, so it passes as same-origin and the Host check is what refuses it; that check stays on. What the Origin check adds is refusing a page on another site that relies on what the browser attaches by itself (a cookie, or the reach of a server on localhost), which a server requiring a bearer token on every request does not accept. The docs state that condition.

The TypeScript SDK arms its Host and Origin validation separately, so the same setup is already possible there.

Resolves #684.

How Has This Been Tested?

test/mcp/server/transports/streamable_http_transport_test.rb; the test that sends three foreign Origin values with allowed_origins: :any gets 403 on the previous library.

Breaking Changes

A Symbol passed as allowed_origins: was accepted before and matched no Origin. :any now turns the Origin check off, and another Symbol raises ArgumentError at construction.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

…` check

## Motivation and Context

`StreamableHTTPTransport` accepts a cross-origin request only when its `Origin` is listed in `allowed_origins:`.
A remote server that browser-based clients on any origin may call, authenticated by a bearer token alone, had two ways
to admit them: `dns_rebinding_protection: false`, which also turns off the `Host` check, or building the transport
per request with that request's own `Origin` in the list.

`allowed_origins: :any` now skips the `Origin` check alone. A rebound request names the attacker's host in `Host` and, if sent,
`Origin`, so it passes as same-origin and the `Host` check is what refuses it; that check stays on. What the `Origin` check
adds is refusing a page on another site that relies on what the browser attaches by itself (a cookie, or the reach
of a server on localhost), which a server requiring a bearer token on every request does not accept. The docs state
that condition.

The TypeScript SDK arms its Host and Origin validation separately, so the same setup is already possible there.

Resolves modelcontextprotocol#684.

## How Has This Been Tested?

`test/mcp/server/transports/streamable_http_transport_test.rb`; the test that sends three foreign `Origin` values
with `allowed_origins: :any` gets 403 on the previous library.

## Breaking Changes

A Symbol passed as `allowed_origins:` was accepted before and matched no `Origin`.
`:any` now turns the `Origin` check off, and another Symbol raises `ArgumentError` at construction.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StreamableHTTPTransport: option to accept any Origin and keep the Host check

1 participant