MCPSafe.io
RegistryThreatsMethodologyDocsPricingScanSign in
MCPSafe.io

Security checks for MCP servers — public packages and private repos, fast or deep.

Legal

Privacy PolicyCookie PolicyTerms of ServiceSecurity disclosure

Resources

State of MCP SecuritySupportSystem statusMade in Germany 🇩🇪

© 2026 MCPSafe. All rights reserved.

GDPR — Privacy Policy
← Threat Catalog

Configuration & Environment

Local HTTP transport without authentication

HIGHCWE: CWE-306Rule: MCP-268

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

What it is

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.

Why it matters for MCP

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.

Vulnerable example

example.py
1
import uvicorn
2
from fastmcp import FastMCP
3
4
mcp = FastMCP("my-mcp")
5
6
@mcp.tool()
7
def echo(message: str) -> str:
8
    return message
9
10
if __name__ == "__main__":
11
    uvicorn.run(mcp.app, host="127.0.0.1", port=8000)

Secure example

example.py
1
import uvicorn
2
from fastapi import Request, HTTPException
3
from fastmcp import FastMCP
4
5
mcp = FastMCP("my-mcp")
6
7
@mcp.app.middleware("http")
8
async def require_bearer(request: Request, call_next):
9
    auth = request.headers.get("Authorization", "")
10
    if not auth.startswith("Bearer "):
11
        raise HTTPException(401)
12
    return await call_next(request)
13
14
@mcp.tool()
15
def echo(message: str) -> str:
16
    return message
17
18
if __name__ == "__main__":
19
    uvicorn.run(mcp.app, host="127.0.0.1", port=8000)

How MCPSafe detects this

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.

Further reading

  • MCP Security Best Practices — Local Server Compromise
  • CWE-306: Missing Authentication for Critical Function

Scan an MCP server for this issue

MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.

Scan now