Skip to content

fix(server): do not crash the SSE server process on an invalid Host/Origin - #3663

Closed
KaiyiQuan wants to merge 4 commits into
modelcontextprotocol:mainfrom
KaiyiQuan:fix/3661-sse-validation-crash
Closed

KaiyiQuan wants to merge 4 commits into
modelcontextprotocol:mainfrom
KaiyiQuan:fix/3661-sse-validation-crash

Conversation

@KaiyiQuan

Copy link
Copy Markdown

Closes #3661

Bug: a single request to /sse with a disallowed Host/Origin header (DNS-rebinding protection, enabled by default for localhost-bound servers) crashed the whole server process. connect_sse sends the rejection response (421/403) and then raise ValueError to signal that no SSE session was established, but MCPServer.sse_app()'s handle_sse had no handler — the exception escaped the ASGI callable and uvicorn took down every connected client (one-request DoS).

Fix (matching the direction suggested in the report):

  1. handle_sse catches ValueError from the async with sse.connect_sse(...) block and returns: the rejection response has already been sent to that one client, so the server just keeps serving everyone else. The exception is logged at debug level.
  2. Documented connect_sse's send-then-raise contract so other callers know to handle it (the raise itself is kept — it's asserted by existing transport-level tests such as test_sse_connect_rejects_a_disallowed_host).

Verification:

  • New regression test drives MCPServer.sse_app() through the in-process ASGI bridge: a disallowed Host gets 421, and a subsequent request to an unmatched route is still served (404) — the app did not crash.
  • tests/server/ full suite passes (1367 tests); SSE security suite 32/32.

KaiyiQuan added 4 commits October 9, 2026 18:09
…rigin

When a request to /sse fails the transport-security checks (DNS-rebinding
protection: disallowed Host -> 421, disallowed Origin -> 403), connect_sse
sends the rejection response and then raises ValueError to signal the
caller that no SSE session was established. FastMCP.sse_app()'s handle_sse
had no handler for it, so the exception escaped the ASGI callable and
uvicorn crashed the whole server process -- one malformed request killed
every client (reported in modelcontextprotocol#3661 via ida-pro-mcp's idalib-mcp).

Catch ValueError in handle_sse: the rejection response has already been
sent to that one client, so just return. Also document connect_sse's
send-then-raise contract so future callers know to handle it.

Adds a regression test driving MCPServer.sse_app() with a disallowed Host
through the in-process ASGI bridge: 421 returned and no exception escapes.
32 server/security tests pass (1367 in tests/server/).
Copilot AI balanced review requested due to automatic review settings October 9, 2026 10:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md) label Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

This PR has been closed automatically. This repo only keeps pull requests open when they come from a maintainer, or from a contributor a maintainer has assigned to the linked issue, and you aren't currently assigned to #3661.

If a maintainer assigns you to #3661, this PR reopens on its own and there's nothing more you need to do here. Assignment is a maintainer call based on capacity; comments that only ask to be assigned don't factor in. What does help is engaging on the issue itself by confirming the repro, explaining why it matters for your use case, or describing the approach you'd take.

You're welcome to keep pushing commits here (just avoid force-pushing, since GitHub can't reopen a rewritten branch), but that on its own won't get the PR reviewed or the issue assigned, and realistically most auto-closed PRs stay closed. There's no need to open a new PR either way.

CONTRIBUTING.md has the full reasoning, but in short:

  • We're a small team with very little capacity to review community PRs right now.
  • Many recent PRs are AI-generated with little human review, and reviewing one carefully still costs a maintainer as much time as it ever did. A well-described issue is usually more useful to us than the code.

Maintainers: reopen, remove missing-issue-link, or add bypass-issue-check to override.

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

Labels

missing-issue-link Auto-closed: PR needs a linked issue assigned to its author (see CONTRIBUTING.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SSE transport: invalid Host/Origin header on /sse crashes entire server process, not just that request

2 participants