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

**Short answer:** 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.

## Checklist
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.
2. 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).
3. 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.
4. 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.
5. 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.
6. 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.
7. 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.
8. 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.
- The MCP Streamable HTTP security warning says that without Origin validation, localhost binding and authentication, attackers could use DNS rebinding to interact with local MCP servers from remote websites. The MCP security best practices list an insecure local server left running on localhost as one of the ways local servers are compromised.

## 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.
- MCP Security Best Practices, Local MCP Server Compromise: servers intended to run locally SHOULD prevent unauthorized use by malicious processes by using stdio, or, over HTTP, by requiring an authorization token or using unix domain sockets or other restricted IPC.

## 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.
- In the current SDK, createMcpExpressApp() defaults to host 127.0.0.1 and applies Host validation for 127.0.0.1, localhost and ::1, plus Origin validation that rejects a present non-localhost Origin with 403 before the request body is read. Binding to 0.0.0.0 or :: only logs a warning unless you pass allowedHosts.

## Ask Rightshold (free, no key)
Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code (one-click setup: https://www.rightshold.com/start?ref=seo), 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?"

```json
{
  "tool": "precall_check",
  "arguments": {
    "url": "<the MCP server's https URL>"
  }
}
```
- The answer combines the external registry entry, a live integrity probe against the recorded tool fingerprint, an invisible-text scan of the definitions and any security flags. It is evidence to decide from, never a finding that a server is safe.
- check_tool_integrity shows tools added, removed or changed since the definitions were recorded, so a server that starts exposing new tools after an update is visible before your agent uses them.
- Delegated and intent keys on Rightshold follow the same rule as a local server token: an agent gets only the scopes its task needs, never the owner's full key.

_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._

## Sources
- [MCP specification (2025-11-25): Transports, Streamable HTTP security warning](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports)
- [MCP Security Best Practices: Local MCP Server Compromise](https://modelcontextprotocol.io/docs/tutorials/security/security_best_practices)
- [GitHub advisory GHSA-w48q-cv73-mx4w: DNS rebinding protection disabled by default in the MCP TypeScript SDK (CVE-2025-66414)](https://github.com/modelcontextprotocol/typescript-sdk/security/advisories/GHSA-w48q-cv73-mx4w)
- [MCP TypeScript SDK: createMcpExpressApp source (Host and Origin validation)](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/packages/middleware/express/src/express.ts)

## Related
- [How to vet an MCP server before installing it](https://www.rightshold.com/answers/how-to-vet-an-mcp-server-before-installing-it)
- [How to share one MCP server across a company with per-user auth](https://www.rightshold.com/answers/how-to-share-one-mcp-server-across-a-company-with-per-user-auth)
- [MCP OAuth: rejecting wrong-audience tokens](https://www.rightshold.com/answers/mcp-oauth-wrong-audience-tokens)
- [How to log every AI agent tool call for audit](https://www.rightshold.com/answers/how-to-log-every-ai-agent-tool-call-for-audit)

_Not legal advice. Updated 2026-10-30. JSON: https://www.rightshold.com/answers/how-to-protect-a-local-mcp-server-from-dns-rebinding.json_