Skip to content

fix: Restrict MCP HTTP transport to localhost, add origin validation#1

Open
taylorodell wants to merge 1 commit into
cloudinary:mainfrom
taylorodell:fix/restrict-transport-binding
Open

fix: Restrict MCP HTTP transport to localhost, add origin validation#1
taylorodell wants to merge 1 commit into
cloudinary:mainfrom
taylorodell:fix/restrict-transport-binding

Conversation

@taylorodell

Copy link
Copy Markdown

Summary

This PR fixes a security vulnerability where both the Streamable HTTP (serve) and SSE (start) transports bind to 0.0.0.0 with wildcard CORS (Access-Control-Allow-Origin: *), exposing the MCP server to DNS rebinding and LAN-based attacks.

The Problem

  1. 0.0.0.0 bind exposes the server to the entire local network
  2. ACAO: * allows any webpage to make cross-origin requests to the MCP server
  3. No origin validation means a malicious page (via DNS rebinding) or any LAN device can invoke all MCP tools with the victim's Cloudinary API credentials

Combined, a user running the server with their API credentials (as shown in DOCKER.md) is vulnerable to credential theft from any browser tab they have open.

Precedent: HackerOne resolved report — "DNS Rebinding SSRF in Burp Suite MCP Server" ($2,000 bounty)

Changes

  • Default bind changed from 0.0.0.0 to 127.0.0.1 (both serve and start commands)
  • Added --host CLI flag for users who explicitly need network access (e.g., Docker)
  • Removed wildcard CORS — replaced with origin validation middleware
  • Added --allowed-origins flag (serve command) for users who need cross-origin access from known clients
  • Updated DOCKER.md — Docker examples now use --host 0.0.0.0 (required inside containers) with -p 127.0.0.1:2718:2718 for localhost-only exposure
  • Added Security Considerations section to DOCKER.md
  • Warning logged when --host 0.0.0.0 is used explicitly

Breaking Change Note

Users running the server with network access will need to add --host 0.0.0.0 explicitly. The default is now localhost-only, which is the correct security posture for a credential-bearing local server.

Testing

  • TypeScript compilation: ✅ passes (npx tsc --noEmit)
  • ESLint: ✅ no violations
  • Existing behavior preserved for localhost usage (no CORS needed for same-origin)
  • Docker usage documented with required --host 0.0.0.0 flag

…dcard CORS

- Change default bind address from 0.0.0.0 to 127.0.0.1 for both
  serve (Streamable HTTP) and start (SSE) commands
- Remove Access-Control-Allow-Origin: * wildcard CORS header
- Replace with origin validation middleware that only sets CORS headers
  for explicitly allowed origins via --allowed-origins flag
- Add --host CLI flag to both commands for users who need network access
- Add --allowed-origins flag to serve command for cross-origin clients
- Log a warning when --host 0.0.0.0 is used explicitly
- Update DOCKER.md examples to use --host 0.0.0.0 (required inside
  containers) and recommend -p 127.0.0.1:2718:2718 for localhost-only
  port exposure
- Add Security Considerations section to DOCKER.md

Without these changes, the MCP server is vulnerable to DNS rebinding
attacks: a malicious webpage can use DNS rebinding to make cross-origin
requests to the locally-running server, gaining full access to all MCP
tools with the victim's Cloudinary API credentials. The wildcard CORS
policy (ACAO: *) further enables direct cross-origin exploitation from
any webpage without DNS rebinding.

Precedent: HackerOne #2len resolved (Burp Suite MCP DNS rebinding).
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.

1 participant