Get a demo — 30 minutes →
← Back to blog
Anomity robot illustrating Why Local MCP HTTP Keep Falling to DNS Rebinding
Insights

Why Local MCP HTTP Keep Falling to DNS Rebinding

TL;DR
  • Local MCP HTTP is a class, not two one-off CVEs: packages expose SSE or Streamable HTTP, bind loopback or all interfaces, and forget the SDK Host/Origin allowlists that exist specifically to stop DNS rebinding.
  • CVE-2026-59971 (mysql-mcp-server SSE, CVSS 10.0) and CVE-2026-61568 (@zereight/mcp-gitlab Streamable HTTP, CVSS 9.6) both shipped without enabling those controls - weeks apart, same hinge.
  • Loopback bind ≠ browser boundary. A page the user opens can rebind DNS to 127.0.0.1 and speak MCP unless Host/Origin are enforced before initialize.
  • Token checks after initialize (for example REMOTE_AUTHORIZATION) do not replace refusing the cross-origin localhost session at the HTTP layer.
  • Defenders should inventory MCP URLs and transports, prefer stdio when HTTP is unnecessary, require Host/Origin allowlists on every HTTP MCP, and deny unsafe tools/call at the agent hook.

Two critical MCP CVEs in the same September window tell one story. MySQL MCP Server CVE-2026-59971 disabled Origin/Host protection on SSE and bound 0.0.0.0. GitLab MCP CVE-2026-61568 created Streamable HTTP without enableDnsRebindingProtection on 127.0.0.1. Different packages, different languages, same class: local MCP HTTP without a browser origin boundary.

Loopback is not a security control against the browser

Developers hear "binds to localhost" and stop worrying. Browsers do not. DNS rebinding exists to make a page the user opened speak to a service on loopback while presenting Host and Origin values the page chooses. If the MCP HTTP stack does not reject those headers before initialize, the local agent tooling becomes a cross-origin API. DNS rebinding is not the only road to loopback: OpenCode's local server fell to a plain cross-site form navigation, with no rebinding at all.

That is why SDK authors added allowlists. The Python SSE path wants security_settings. The TypeScript Streamable HTTP path wants enableDnsRebindingProtection plus allowedHosts / allowedOrigins. When constructors omit them - as both CVEs did - the protection is off by construction. Auth middleware that only checks tokens on tools/call still lets the session form.

How this rhymes with other MCP HTTP failures

Unauthenticated or weakly bounded MCP HTTP is a familiar theme: Windows MCP PowerShell RCE, Weknora unauthenticated MCP RCE, MCP Inspector proxy unauth RCE, Grafana MCP session spoofing/SSRF, and LiteLLM MCP OAuth passthrough. Some are missing auth entirely; some are gateway identity mistakes; the September pair is specifically forgotten DNS-rebinding allowlists. The operational lesson is identical: treat every MCP HTTP listener as internet-adjacent to the browser until Host/Origin enforcement is verified.

stdio-by-design risks are a different door - see Anthropic MCP stdio by-design RCE - but teams often flip to HTTP for "modern" agent clients and inherit this class overnight. Registry hygiene from how to build an MCP server registry helps you know which servers exist; it does not enable the allowlists for you.

What to change before the next CVE

  • Inventory MCP URLs and transports on every developer endpoint - SSE, Streamable HTTP, and odd localhost ports.
  • Prefer stdio for single-user local agents when HTTP buys nothing.
  • Require Host/Origin allowlists (and authenticated reverse proxies) on any HTTP MCP that must stay.
  • Do not equate token middleware with browser-boundary rejection - initialize must fail closed for unexpected Origin/Host.
  • Deny high-impact tools/call at the agent hook even when the MCP server is "only local."
  • Re-hash tools/list over time so runtime drift - as in Deadbugz - does not hide behind a clean first connect.

How Anomity closes the local MCP HTTP gap

Anomity's Endpoint Sensor inventories MCP servers among the eight AI artifact types so localhost HTTP listeners and package versions are queryable across the fleet. Browser Sensor and cloud discovery (Google Workspace / GitHub OAuth grants) cover adjacent AI surfaces. On agents that expose PreToolUse-style hooks, runtime governance returns allow, deny, or log before a dangerous call runs - including GitLab variable dumps or unrestricted SQL tools steered after a rebound session. Decisions land in a 90-day audit trail to SIEM, Slack, email, or Jira. SOC 2 Type II; complements Network, EDR, DLP, and GRC.

The SDK already had the switches. The packages forgot them. Inventory the listeners, enforce the allowlists, and book a 30-minute demo to see which MCP HTTP endpoints your fleet still exposes.

Frequently asked questions

What is the local MCP HTTP DNS-rebinding class?

It is the recurring pattern where an MCP server listens on HTTP (SSE or Streamable HTTP), often on loopback, without effective Host or Origin validation. A malicious webpage uses DNS rebinding so the browser sends requests to the victim's local listener while presenting attacker-controlled headers. The MCP stack treats that as a legitimate client unless the SDK allowlists are enabled.

Why do package authors keep missing the SDK flags?

The MCP SDKs expose enableDnsRebindingProtection and allowedHosts/allowedOrigins (or security_settings equivalents), but defaults and sample code often omit them. Authors copy a transport constructor that "works on localhost" in a happy-path demo, ship it, and never turn on the browser-boundary controls. Reviewers who only test curl from the same host also miss the failure.

Is binding to 127.0.0.1 enough?

No. DNS rebinding exists specifically to reach loopback services from a page the user navigated to. Binding all interfaces (0.0.0.0) is worse because direct network exposure needs no rebinding. Either way, Host and Origin validation must reject unexpected browser origins before MCP initialize.

How should teams govern this without waiting for the next CVE?

Inventory every MCP URL and transport on developer endpoints. Prefer stdio for local agents. Require Host/Origin allowlists and authenticated fronts for any HTTP MCP. Continuously compare tools/list metadata, and evaluate resulting tool calls at the agent hook with allow, deny, or log. Treat localhost MCP ports as browser-reachable until proven otherwise.

How does Anomity help with this class?

Anomity inventories MCP servers and transports on managed endpoints, so SSE and Streamable HTTP listeners are fleet-visible. Runtime governance denies or logs unsafe tool calls at hooks such as Claude Code PreToolUse before they run. A 90-day audit trail routes to SIEM, Slack, email, or Jira. Metadata only; secrets redacted on-endpoint. Complements Network, EDR, DLP, and GRC rather than replacing them.

Ask AI about Anomity
ChatGPT Claude Perplexity Google AI Grok