Summary
The WebSocket server binds to all network interfaces (0.0.0.0:9009) instead of localhost (127.0.0.1:9009), allowing anyone on the local network to send browser control commands.
Impact
On shared networks (coffee shops, offices, hotels), an attacker on the same network can:
- Navigate the browser to arbitrary URLs
- Click elements, type text, take screenshots
- Read page content via snapshots
- Execute any browser automation command
Reproduction
# Start the MCP server
npx @browsermcp/mcp@latest
# On the same machine or any machine on the local network:
ss -tlnp | grep 9009
# Shows: LISTEN *:9009 (bound to all interfaces)
Root Cause
In src/ws.ts:
async function createWebSocketServer(port = mcpConfig.defaultWsPort) {
// ...
return new WebSocketServer({ port }); // No host parameter
}
The ws library defaults to 0.0.0.0 when no host is specified.
Suggested Fix
return new WebSocketServer({ port, host: '127.0.0.1' });
Or better, add a --host flag with secure default:
program
.option('--host <host>', 'Host to bind to', '127.0.0.1')
.option('--port <port>', 'Port to bind to', '9009')
Comparison
Other MCP servers handle this correctly:
@playwright/mcp - binds to localhost by default
browserbase/mcp-server-browserbase - has --host flag, defaults to localhost
Environment
- Package:
@browsermcp/mcp@0.1.3
- OS: Linux (also affects Windows/macOS)