fix: reject requests with missing Origin header in origin validation middleware (CWE-346)#1161
Open
sebastiondev wants to merge 1 commit intomodelcontextprotocol:mainfrom
Conversation
…middleware The originValidationMiddleware only checked whether a present Origin header matched the allowlist. When the Origin header was absent (as with curl, scripts, or any non-browser HTTP client), the check was skipped entirely, allowing unauthenticated access to all protected endpoints. Changed the condition from `if (origin && !allowedOrigins.includes(origin))` to `if (!origin || !allowedOrigins.includes(origin))` so that requests without an Origin header are also rejected with 403 Forbidden. This prevents non-browser CSRF and unauthorized access from tools that do not send an Origin header, which is especially critical when combined with DANGEROUSLY_OMIT_AUTH=true. CWE-346: Origin Validation Error
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Vulnerability Summary
CWE: CWE-346 — Origin Validation Error
Severity: High (when auth is disabled); Low (when auth is enabled, the default)
Affected file:
server/src/index.ts,originValidationMiddleware(line ~206)Data Flow
The
originValidationMiddlewareis applied to 7 routes (/mcp,/stdio,/sse,/message,/config) and runs beforeauthMiddleware. The current condition:uses a fail-open pattern — when the
Originheader is absent (i.e.undefined), the entire check is skipped andnext()is called, allowing the request through without origin validation.This is exploitable via DNS rebinding: same-origin requests from a rebound domain do not include an
Originheader, so the middleware passes them through. When combined withDANGEROUSLY_OMIT_AUTH=true(a documented configuration option), the/stdioendpoint can be reached, which spawns local processes viaStdioClientTransport— leading to remote code execution.Exploit Sketch (DNS Rebinding + Auth Disabled)
DANGEROUSLY_OMIT_AUTH=true npx @modelcontextprotocol/inspectorevil.comin their browserevil.comresolves to127.0.0.1after TTL expiresevil.com:6277/stdio?transportType=stdio&command=bash&args=-c%20idif (undefined && ...) → false→next()→ request passesauthMiddlewarecallsnext()bash -c "id"→ RCEPreconditions
DANGEROUSLY_OMIT_AUTH=true(documented in README)When auth is enabled (default), the origin bypass alone is not independently exploitable because the 256-bit random auth token cannot be guessed.
Fix Description
One-line change — converts fail-open to fail-closed:
Rationale
Origin→ condition isfalse→ request passes (fail-open)Origin→!originistrue→ request is rejected with 403 (fail-closed)Originheader continue to work exactly as before15ecb59by Felix Weinberger)Test Results
The fix was validated by tracing the logic for all three cases:
http://localhost:6274)http://evil.com)undefined)The change is minimal (1 line, 1 file) and does not alter any other behavior.
Disprove Analysis
We systematically attempted to disprove the finding across 9 dimensions:
Auth Check
Strong auth exists:
authMiddlewarerequires aX-MCP-Proxy-Auth: Bearer <token>header with a 256-bit random token verified viatimingSafeEqual. However, auth can be disabled withDANGEROUSLY_OMIT_AUTH=true, a documented and actively used option.Network Check
Server binds to
localhostby default, limiting direct network access. However, DNS rebinding bypasses localhost binding — that is precisely whatoriginValidationMiddlewarewas designed to prevent. Docker usage withHOST=0.0.0.0(documented in README, discussed in issue #639) further exposes the server.Deployment Context
Dockerfile exists. The Docker example in README uses
-e HOST=0.0.0.0. The proxy server can spawn local processes via the/stdioendpoint.Caller Trace
originValidationMiddlewareis applied to all 7 protected routes, always beforeauthMiddleware. The/stdioendpoint callscreateTransport()which can spawn arbitrary local processes.Prior Reports
HOST=0.0.0.0encountering origin-related errorsCommit History
The
originValidationMiddlewarewas added in commit15ecb59with the explicit purpose of preventing DNS rebinding. The buggyif (origin && ...)logic was present from the very first commit of this middleware.Mitigations Found
cors()uses permissive defaults (Access-Control-Allow-Origin: *) — does not help; noted as an issue in open PR server: restrict default CORS to allowed origins #1074Fix Adequacy
The fix changes the only origin validation point. When auth is disabled, origin validation is the sole defense against browser-based attacks. No parallel path provides equivalent protection.
Verdict
CONFIRMED_VALID — High confidence. The vulnerability is a clear fail-open logic error. The fix is minimal, correct, and directly addresses the root cause.
Related
Disclosure: This issue was identified through automated security analysis. The project's
SECURITY.mdrequests disclosure through GitHub Security Advisories; however, this is a one-line logic fix for a publicly visible code pattern, and a PR enables transparent review by maintainers.