Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

Make Origin validation opt-in in the app factories (keep Host validation on for localhost)

未關閉
#3,576 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

評估

難度
4/5
預估耗時
3-5 天
新手友好度
45/100
Issue 類型
功能
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
python
領域
backend, security

研究方向

The change is in TransportSecurityMiddleware, likely in mcp/server/transport_security.py or a similar module. Start by reading the middleware's current Host and Origin validation logic. The fix involves making Origin validation conditional on a non-empty allowed_origins list and removing default localhost allowed_origins in MCPServer and lowlevel.Server. Test with browser extension clients to verify Origin headers no longer cause 403 errors. Update docs/run/deploy.md to reflect the new behavior.

由索引模型根據 Issue 內容生成。

描述

Description

When enable_dns_rebinding_protection=True, TransportSecurityMiddleware checks Host and Origin together. It can't do one without the other, and an empty allowed_origins means any request that carries an Origin header is rejected. MCPServer and lowlevel.Server also turn this on by default for localhost binds, with a localhost-only allowed_origins.

This blocks browser-based MCP clients such as extensions. A Chrome extension sends Origin: chrome-extension://<id>. The same request with the same credentials gets 200 without an Origin header and 403 with one. The only fix is for every server operator to allowlist each client by hand.

The Origin check doesn't add rebinding protection. The DNS-rebinding advisory (GHSA-9h52-p55h-vw2f) is closed by the Host check. An Origin check is a CSRF control, and it only matters when the server accepts credentials the browser sends automatically, such as cookies. The full threat model is in modelcontextprotocol/modelcontextprotocol#3370.

The Go SDK made this change already. Host protection on loopback is on by default. Origin protection was on by default in v1.4.1 through v1.5.0 and has been off since v1.6.0. The setting that could restore it was removed in v1.8.0.

Proposal:

  • Validate Origin only when allowed_origins is non-empty. An empty list means no Origin check, not reject-all.
  • Drop the default localhost allowed_origins in MCPServer and lowlevel.Server.
  • Host validation and its defaults are unchanged. When the Origin check is on, Origin: null is still rejected.
  • Update docs/run/deploy.md to describe allowed_origins as the CSRF control and allowed_hosts as the DNS-rebinding control.

This doesn't reopen CSRF on unauthenticated localhost servers. The middleware already returns 400 for any POST whose Content-Type isn't application/json, and a cross-site JSON POST forces a CORS preflight. I'd add a test that pins this.

Compatibility: there are two behaviour changes, and I'd like a maintainer's view on whether a 2.x minor release is OK for them.

  • Localhost servers using the defaults would no longer reject cross-origin requests that pass the Host and Content-Type checks.
  • Anyone who sets allowed_hosts without allowed_origins would no longer reject every request that carries an Origin header.

In both cases, setting allowed_origins explicitly restores today's behaviour.

Further proposals

  1. Scheme wildcards in allowed_origins. Once Origin validation is opt-in, an operator who turns it on still has to list every browser-extension client by hand. That's impossible for Firefox, whose moz-extension://<uuid> origin differs on every install. Proposal:

    • An entry of the form "<scheme>://*" matches any Origin with that scheme, for example "chrome-extension://*" or "moz-extension://*".
    • Exact entries and the existing :* port wildcard keep working as today.
    • "http://*" and "https://*" raise a ValueError, because they would allow every website. Leaving allowed_origins empty already does that.
    • This would build on the fix for #3463 (the :* suffix bug), since it touches the same matcher.
  2. A machine-readable reason in the rejection body. Today a Host rejection is 421 Invalid Host header and an Origin rejection is 403 Invalid Origin header, both as plain text. A client can't reliably tell these from an auth failure, so it can't tell the user that signing in again won't help. Proposal: keep the status codes, but return a JSON-RPC error body whose data.reason carries a stable code:

    { "jsonrpc": "2.0", "error": { "code": -32000, "message": "Invalid Origin header", "data": { "reason": "invalid_origin" } }, "id": null }
    

    The reason values would match the ones the TypeScript SDK already computes internally (missing_host, invalid_host, invalid_origin_header, invalid_origin), so clients can handle both SDKs the same way.

Disclosure: drafted with Claude Code;

主要語言
Python
星號
24.3k
分支
4k
平均合併
1 天 16 小時
30 天內合併 PR
25

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

modelcontextprotocol/python-sdk 的其他 Issue

查看 modelcontextprotocol/python-sdk 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。