Vendor toolingHighSecurity exploitPrompt injection

browse-mcp arbitrary file write via unconfined download/state paths, reachable through indirect prompt injection

Undisclosed·browse-mcp (Playwright-based headless-browser MCP server)Fixed

browse-mcp's browser_download tool wrote a fetched response body to join(save_dir, filename) without validating the caller-controlled save_dir, and browser_save_state/browser_load_state honored an explicit path unchanged, so a malicious MCP client or an agent steered by indirect prompt injection on a visited page could choose an arbitrary save_dir/path plus a URL whose response body became the file contents, writing attacker-controlled bytes to any path the process could reach (e.g. ~/.bashrc, an autostart entry, or a cron file); a force_fetch fallback also used a raw fetch() that bypassed the BROWSE_MCP_ALLOWED_ORIGINS origin fence.

Blast radius
Arbitrary file write with potential host code execution on any machine running an unpatched browse-mcp server (<=0.8.1); no specific victim organisation or exploitation-in-the-wild was disclosed in the advisory.
Root cause
MCP tool arguments (save_dir/path for downloads and state files) were passed straight into filesystem join/write calls with no path confinement or traversal checks, and a fallback fetch path bypassed the configured origin allowlist entirely.
How it was caught
Found and privately reported by a security researcher (credited as 'novice-22') rather than caught in production use.
What changed
Fixed in browse-mcp 0.8.2: save_dir is confined under ~/.browse-mcp/downloads and explicit state paths under ~/.browse-mcp/state, with absolute paths and '..' escapes rejected; the advisory notes that hiding tools via an allowlist does not stop a malicious MCP client from calling them by name, so upgrading is the actual fix.

Take-awayNever let an agent-facing tool pass caller-supplied paths straight into filesystem writes — canonicalize and confine every save/load path to a fixed root before use, and don't rely on an origin/tool allowlist as a substitute for real input validation.

First surfaced: Security advisory · Recorded