v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
MEDIUM AI PREVALENCE: MEDIUM auth.py.mcp.dns-rebinding-unprotected

This FastMCP server binds to 0.0.0.0 and serves a network transport (streamable-http / SSE) without DNS-rebinding protection (CWE-346).

Why AI tools produce this: AI coding tools produce this regularly, typically when prompted for a shortcut or a quick fix.

Why this matters

When the host is not loopback, the SDK does NOT auto-enable protection, so a web page the user visits can rebind a DNS name to this server and drive its tools cross-origin. (Binding to 127.0.0.1 auto-protects since 1.23.0.)

Pass explicit transport security with a Host allow-list: from mcp.server.transport_security import TransportSecuritySettings mcp = FastMCP( "name", host="0.0.0.0", transport_security=TransportSecuritySettings( enable_dns_rebinding_protection=True, allowed_hosts=["mcp.example.com"], allowed_origins=["https://app.example.com"], ), )

VULNERABLE
vulnerable.py
from mcp.server.fastmcp import FastMCP

# ruleid: auth.py.mcp.dns-rebinding-unprotected
mcp = FastMCP("weather", host="0.0.0.0", port=8000)


@mcp.tool()
def forecast(city: str) -> str:
    return "sunny"


mcp.run(transport="streamable-http")


# ruleid: auth.py.mcp.dns-rebinding-unprotected
sse = FastMCP("events", host="0.0.0.0")
sse.run(transport="sse")
SAFE
safe.py
from mcp.server.fastmcp import FastMCP
from mcp.server.transport_security import TransportSecuritySettings

# Explicit transport security with a Host allow-list: safe.
mcp = FastMCP(
    "weather",
    host="0.0.0.0",
    transport_security=TransportSecuritySettings(
        enable_dns_rebinding_protection=True,
        allowed_hosts=["mcp.example.com"],
        allowed_origins=["https://app.example.com"],
    ),
)
mcp.run(transport="streamable-http")


# Loopback bind auto-protects since 1.23.0: out of scope, safe.
local = FastMCP("local", host="127.0.0.1")
local.run(transport="streamable-http")

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

# oauthlint-disable-next-line auth.py.mcp.dns-rebinding-unprotected -- <reason>

References

https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization ↗https://www.cve.org/CVERecord?id=CVE-2025-66416 ↗https://cwe.mitre.org/data/definitions/346.html ↗