Rightshold™ Sign up

Answers · MCP security

How do I protect a local MCP server from DNS rebinding?

Last updated

TL;DR: Use stdio if you can; DNS rebinding only matters for MCP servers that listen on HTTP. If you run Streamable HTTP locally, do three things the MCP specification's security warning asks for: validate the Origin header on every connection and answer 403 Forbidden when it is present and not yours, bind to 127.0.0.1 (or ::1) instead of 0.0.0.0, and require authentication on every request, for example a random bearer token the client is given at startup. Also check the Host header against an allowlist such as localhost and 127.0.0.1 with your port, because a rebinding page sends its own domain as Host. Without these, a website you visit can point its domain at 127.0.0.1 and call your server's tools from your browser. In the MCP TypeScript SDK, versions before 1.24.0 left this protection off by default (CVE-2025-66414); createMcpExpressApp() now turns on Host and Origin validation when you bind to 127.0.0.1, localhost or ::1, and only warns when you bind to 0.0.0.0.

What should I check, step by step?

1. Prefer the stdio transport for servers that only your own MCP client launches; the MCP security best practices say to use stdio to limit access to just the MCP client, and the TypeScript SDK advisory notes stdio servers are not affected.

  1. Bind HTTP servers to 127.0.0.1 or ::1, never 0.0.0.0 or ::, unless other machines genuinely need access (and then put real authentication and TLS in front).
  2. Validate Origin on every request: if an Origin header is present and is not an origin you expect, return HTTP 403 Forbidden. Requests from non-browser clients usually send no Origin, so Origin checks alone are not authentication.
  3. Validate Host against an allowlist (for example localhost:PORT, 127.0.0.1:PORT, [::1]:PORT). After a rebind the browser still sends the attacker's domain as Host, so a strict Host check stops the request.
  4. Require a token on every request: generate a random secret at startup, hand it to the client out of band (config file, environment variable) and reject requests without it. The best-practices page lists an authorization token or a unix domain socket as the ways to restrict a local HTTP server.
  5. TypeScript SDK: upgrade @modelcontextprotocol/sdk to 1.24.0 or later and build the app with createMcpExpressApp(); with a custom Express app, add the exported hostHeaderValidation() middleware. If you must bind 0.0.0.0, pass allowedHosts.
  6. Test it: send a request with Host: attacker.example and one with Origin: https://attacker.example and confirm both are refused before any tool runs.
  7. Don't leave dev servers, inspectors or debugging proxies listening after you're done; an idle localhost port is what a rebinding page looks for.

How the attack works

The same-origin policy is based on domain names, not IP addresses. An attacker serves a page from a domain they control, then changes that domain's DNS record to 127.0.0.1. The page's scripts can now send requests to a server on your machine while the browser still treats them as same-origin with the attacker's site.

What does the specification require?

MCP specification 2025-11-25, Transports, Streamable HTTP: servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding; if Origin is present and invalid they MUST respond with HTTP 403 Forbidden; when running locally they SHOULD bind only to localhost (127.0.0.1) rather than all interfaces (0.0.0.0); and they SHOULD implement proper authentication for all connections.

The TypeScript SDK fix (CVE-2025-66414)

GitHub advisory GHSA-w48q-cv73-mx4w (published December 2, 2025, severity high): @modelcontextprotocol/sdk before 1.24.0 did not enable DNS rebinding protection by default, so an unauthenticated localhost server using StreamableHTTPServerTransport or SSEServerTransport without enableDnsRebindingProtection could be called by a malicious website.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Before I connect this MCP server to my agent, is it a listed server, what tools does it expose, and have its tool definitions changed?”

One-click setup

{
  "tool": "precall_check",
  "arguments": {
    "url": "<the MCP server's https URL>"
  }
}

Rightshold cannot reach or scan servers on your localhost and does not configure your server's bind address, headers or tokens; those protections live in your MCP server and its SDK settings.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'