Описание
genieacs-mcp: DNS rebinding reaches local GenieACS MCP Streamable HTTP transport
genieacs-mcp exposes a local Streamable HTTP MCP endpoint that accepts attacker-controlled Host and Origin headers. A malicious web page can use DNS rebinding to route browser requests to a victim's loopback MCP listener while preserving the attacker origin. The server accepts the request, initializes an MCP session, lists GenieACS tools, and can invoke tools against the configured GenieACS NBI without a browser-supplied secret.
The affected package is genieacs-mcp version 0.3.1 at commit 4d7d3c74740efb7f3833aadc8a8e9177650eb462.
The vulnerable transport setup is in cmd/server/main.go. When TRANSPORT is not stdio, the server creates a Streamable HTTP MCP handler:
For the default loopback listener, MCP_AUTH_TOKEN is not required. The unauthenticated branch calls httpSrv.Start(addr) directly. There is no middleware or MCP transport configuration that validates Host or Origin before /mcp handles the request.
The README documents loopback HTTP as the default deployment mode and says MCP_AUTH_TOKEN is required only when MCP_LISTEN_ADDR is non-loopback:
That leaves the browser-origin boundary as the missing control. DNS rebinding is designed to reach loopback listeners from a public web page unless the local server rejects attacker-controlled Host and Origin values.
Proof of concept
The following reproduction uses a fake GenieACS NBI with planted CPE data. It proves that attacker-shaped browser-origin headers reach the real MCP handler and that an MCP tool call reaches the configured GenieACS backend.
Start a fake GenieACS NBI:
In a second terminal, run the affected MCP server:
In a third terminal, send MCP requests with forged browser-origin headers:
The MCP request uses attacker-controlled browser-origin headers and no Authorization header:
Observed output:
tools/list returns 12 tools, including:
The get_parameter tool call reaches the fake GenieACS NBI and returns the planted marker:
The fake GenieACS NBI also records the backend request from the MCP server:
Impact
A malicious website can control a victim's local genieacs-mcp HTTP server when the victim runs the documented default loopback HTTP mode. The page can initialize MCP, list available tools, and invoke GenieACS operations through the server's configured ACS_URL.
In a real deployment, this can expose or modify CPE management state through GenieACS. The exposed tools include device reboot, firmware download task creation, TR-069 parameter changes, preset and provision management, tag changes, connection requests, task deletion, and task retry. Those actions execute with the MCP server's configured GenieACS access.
Why this is a vulnerability, not intended behavior
- The project treats loopback HTTP as a safety boundary. The README documents
127.0.0.1:8080as the default HTTP listen address and requiresMCP_AUTH_TOKENonly for non-loopback listeners. - DNS rebinding bypasses the loopback-only assumption unless the local HTTP server validates
HostandOrigin. - PR #22 added bearer authentication for non-loopback listeners. It explicitly left loopback listeners unauthenticated for compatibility. That protects direct non-loopback exposure, but it does not protect the browser-origin path into a loopback listener.
- A local trusted MCP client is the intended caller. A public web page is not.
Remediation
Add Host and Origin validation before the MCP handler accepts any request. For the default loopback mode, allow only local values such as:
Reject unexpected Host or Origin values before MCP initialization. Treat absent or non-local Origin on browser-reachable requests as suspicious unless the request is authenticated.
Also require a bearer token for HTTP transport even on loopback, or make stdio the default transport and require an explicit opt-in for unauthenticated loopback HTTP.
Пакеты
github.com/geiserx/genieacs-mcp
<= 0.3.1
0.3.2
Связанные уязвимости
genieacs-mcp is an MCP server for GenieACS written in Go. Prior to 0.3.2, the Streamable HTTP transport in cmd/server/main.go creates an unauthenticated /mcp listener on the default MCP_LISTEN_ADDR value 127.0.0.1:8080 when MCP_AUTH_TOKEN is unset and the httpSrv.Start(addr) branch does not validate the Host or Origin headers. A malicious website can use DNS rebinding to send browser requests with attacker-controlled Host and Origin values to the loopback listener, initialize an MCP session, list tools, and invoke operations against the GenieACS NBI configured by ACS_URL. Successful exploitation can expose or modify CPE management state, including device reboots, firmware tasks, TR-069 parameter changes, presets, provisions, tags, connection requests, and task operations. The npm wrapper is not affected because it forces TRANSPORT=stdio and does not expose an HTTP listener. This issue is fixed in version 0.3.2.