Configuration & Environment
An MCP server registers tools and binds an HTTP transport to localhost without any authentication — DNS rebinding lets a malicious web page reach the server from inside the user's browser. Sibling rules covering the same auth-missing-on-transport family: MCP-209 (manifest declaration), MCP-217 (tools/list endpoint).
DNS rebinding is the attack where a malicious website returns its own IP for the first DNS lookup, then re-resolves to `127.0.0.1` for the second — bypassing same-origin policy and reaching localhost services. An unauthenticated HTTP MCP server bound to 127.0.0.1 is reachable from any web page the user visits. The official MCP security best practices recommend either stdio transport (preferred) or auth-token / Unix-domain-socket-restricted HTTP.
Local MCP servers running HTTP for ergonomic reasons (browser-based debugging UIs, REST clients, etc.) trade visibility for safety. An attacker who finds the open port via DNS rebinding can invoke any registered tool — destructive ones included — through the user's browser. Auth tokens or Unix sockets close the gap.
import uvicorn |
from fastmcp import FastMCP |
mcp = FastMCP("my-mcp") |
@mcp.tool() |
def echo(message: str) -> str: |
return message |
if __name__ == "__main__": |
uvicorn.run(mcp.app, host="127.0.0.1", port=8000) |
import uvicorn |
from fastapi import Request, HTTPException |
from fastmcp import FastMCP |
mcp = FastMCP("my-mcp") |
@mcp.app.middleware("http") |
async def require_bearer(request: Request, call_next): |
auth = request.headers.get("Authorization", "") |
if not auth.startswith("Bearer "): |
raise HTTPException(401) |
return await call_next(request) |
@mcp.tool() |
def echo(message: str) -> str: |
return message |
if __name__ == "__main__": |
uvicorn.run(mcp.app, host="127.0.0.1", port=8000) |
MCPSafe flags files that ALL of: (1) register MCP tools (`@mcp.tool` / `mcp.tool()` / `McpServer.tool()`); (2) bind HTTP server to localhost / 127.0.0.1 / [::1] via `uvicorn.run`, `app.run`, `mcp.run(transport="streamable-http|sse|http")`, `StreamableHTTPServerTransport`, `http.createServer.listen`, or `app.listen(port, host)`; (3) lack any auth identifier file-wide (`Authorization`, `Bearer`, `api_key`, `jwt.decode`/`verify`, FastAPI `Depends(*auth*)`, `auth=` kwarg, `verify_token`, `basic_auth`, `X-API-Key`, etc.).
See the full threat catalog for every documented detection.
MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.
Scan now