fix: correct MCP transport security config to actually allow all hosts by default

The MCP library's TransportSecurityMiddleware only supports exact host
matches or "host:*" port wildcards. It does NOT support a standalone "*"
wildcard to mean "allow all hosts" — setting allowed_hosts=["*"] would
reject every connection because no Host header equals "*".

Worse, when transport_security=None was passed to FastMCP while its default
host is "127.0.0.1", FastMCP would auto-enable protection with strict
localhost-only rules, overriding GNS3's intent to allow all hosts.

Root cause analysis:
- FastMCP auto-enables DNS rebinding protection when host is localhost
  and no explicit TransportSecuritySettings is provided
- GNS3 was passing transport_security=None (indirectly via FastMCP's default)
  when protection was disabled, triggering the auto-enable
- The TransportSecuritySettings "allowed_hosts" list does NOT support "*"
  as a catch-all wildcard

This fix:
1. Always pass an explicit TransportSecuritySettings to FastMCP
   - Disabled: TransportSecuritySettings(enable_dns_rebinding_protection=False)
   - Enabled: TransportSecuritySettings(enable_dns_rebinding_protection=True, ...)
2. Restore mcp_allowed_hosts and mcp_allowed_origins config fields
3. Set mcp_enable_dns_rebinding_protection default to False (allow all hosts)

Behaviour:
- Default (no config change): all hosts can connect to MCP server
- With mcp_enable_dns_rebinding_protection=true: only configured hosts
- Aligns with GNS3 server's 0.0.0.0 binding policy
This commit is contained in:
YueGuobin 2026-06-05 23:20:57 +08:00
parent bb39238f02
commit 0e6db9a7b6
No known key found for this signature in database
3 changed files with 28 additions and 23 deletions

View File

@ -106,14 +106,20 @@ def _create_mcp_server() -> FastMCP:
"""Create MCP server with security settings from configuration."""
cfg = Config.instance().settings.Server
mcp = FastMCP(
"GNS3 MCP Server",
transport_security=TransportSecuritySettings(
enable_dns_rebinding_protection=cfg.mcp_enable_dns_rebinding_protection,
allowed_hosts=cfg.mcp_allowed_hosts,
allowed_origins=cfg.mcp_allowed_origins,
),
)
# Always pass an explicit TransportSecuritySettings to prevent FastMCP
# from auto-enabling protection when host is localhost (its default).
if cfg.mcp_enable_dns_rebinding_protection:
transport_security = TransportSecuritySettings(
enable_dns_rebinding_protection=True,
allowed_hosts=cfg.mcp_allowed_hosts or ["127.0.0.1:*", "localhost:*"],
allowed_origins=cfg.mcp_allowed_origins or ["http://127.0.0.1:*", "http://localhost:*"],
)
else:
transport_security = TransportSecuritySettings(
enable_dns_rebinding_protection=False,
)
mcp = FastMCP("GNS3 MCP Server", transport_security=transport_security)
return mcp

View File

@ -185,15 +185,10 @@ cpus = 1.0
; Process limit per container
pids_limit = 1000
; MCP (Model Context Protocol) transport security settings
; Enable DNS rebinding protection for MCP server
mcp_enable_dns_rebinding_protection = True
; Allowed hosts for MCP connections (comma-separated, use * for wildcard)
; Default: * (allow all hosts - recommended for GNS3 VM distribution)
; For enhanced security, restrict to specific hosts: 127.0.0.1:*,localhost:*,192.168.1.3:*
mcp_allowed_hosts = *
; Allowed origins for MCP connections (comma-separated)
; Default: * (allow all origins)
; For enhanced security: http://127.0.0.1:*,http://localhost:*,http://192.168.1.3:*
mcp_allowed_origins = *
; Disabled by default — allows connections from any host (matches GNS3
; server's 0.0.0.0 binding). Enable and configure allowed hosts below
; for enhanced security against DNS rebinding attacks.
; Note: Only "host:*" port wildcards are supported (e.g., "127.0.0.1:*").
;mcp_enable_dns_rebinding_protection = true
;mcp_allowed_hosts = 127.0.0.1:*,localhost:*
;mcp_allowed_origins = http://127.0.0.1:*,http://localhost:*

View File

@ -164,9 +164,13 @@ class ServerSettings(BaseModel):
skills_auto_update: bool = True
# MCP (Model Context Protocol) transport security settings
mcp_enable_dns_rebinding_protection: bool = True
mcp_allowed_hosts: list[str] = Field(default=["*"], description="Allowed Host header values for MCP server")
mcp_allowed_origins: list[str] = Field(default=["*"], description="Allowed Origin header values for MCP server")
# DNS rebinding protection is disabled by default to allow connections
# from any host (aligns with GNS3 server's 0.0.0.0 binding).
# Users with security requirements can enable protection and specify
# allowed hosts using "host:*" port wildcard patterns.
mcp_enable_dns_rebinding_protection: bool = False
mcp_allowed_hosts: list[str] = Field(default_factory=list)
mcp_allowed_origins: list[str] = Field(default_factory=list)
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)