Security
Deny-all by default. Domain allowlist, mutation and eval gates, redaction, the audit log, and the pairing token.
Deny-all safe mode. With no policy configured: empty domain allowlist,
eval off, downloads off, mutating tools off. Opt in explicitly:
chrome-mcp --allow-domain example.com --enable-mutations
chrome-mcp --policy ./policy.json # see policy.example.json
chrome-mcp --unsafe-all-domains # loud footgun
chrome-mcp --enable-observers # console/network/dialog capture (patches page globals)
chrome-mcp --redact # scrub secret-shaped strings out of page readsWhat comes back is gated too. The allowlist decides which pages may be read; it says nothing about what is on them. A logged-in page routinely renders a session token into a script tag or an API key onto a settings screen.
- Password field values are always suppressed — in
get_html, and insnapshot, where the field still appears (so you can type into it) flaggedsecret: truewith no value. No flag, no opt-in: nobody wants those characters. --redactadditionally scrubs secret-shaped strings — JWTs, AWS/GitHub/Slack/ Google keys,Bearerheaders, private-key blocks — out ofget_text,get_html,read_as_markdownandeval. It is opt-in because a pattern will eventually fire on something you actually wanted.--redact-pattern <regex>adds your own (and implies--redact); an invalid one fails at startup rather than silently never matching.- Redaction runs before the output cap, so a truncated read cannot leak what a full one would have hidden.
Every call is recorded to the task's history.jsonl with the URL it touched, the
policy verdict (allowed/denied), how long it took, how many bytes came back,
and how many secrets were scrubbed — so "what did the agent do in my browser" has
an answer after the fact.
The per-boot 256-bit token in ~/.chrome-mcp/handshake.json (mode 0600) is the
only trust boundary; it is never written to stdout/stderr. On POSIX the mode is
re-verified after every write and the server fails closed if the file ends up
group/other-accessible. Windows has no such bits — chmod there only toggles the
read-only attribute — so the check is skipped and the token's confidentiality
rests on the per-user ACL of %USERPROFILE%\.chrome-mcp.
Telemetry
The chrome-mcp server sends anonymous usage statistics to PostHog, so the project can see how many installs are active, which versions and platforms are in use, and which tools fail most. A notice is printed the first time it runs.
What is sent: a random install id (kept in ~/.chrome-mcp/telemetry.json), the
chrome-mcp version, OS, CPU architecture and Node major version, whether the
session owns the bridge port or shares it, how many browsers are paired, and
per-tool call and error counts with error codes — batched every 10 minutes.
What is never sent: URLs, domains, tool arguments, page content, screenshots, cookies, profile names, tokens, file paths, or anything you type. Events are personless and GeoIP lookup is disabled.
The browser extension sends nothing — it only ever talks to 127.0.0.1.
Turn it off with any of:
CHROME_MCP_TELEMETRY=0 # or false / off
DO_NOT_TRACK=1
--no-telemetry # server flagPolicy file
Pass --policy ./policy.json to configure everything in one place. The example shipped with the package:
{
"allowDomains": ["example.com", "*.wikipedia.org"],
"allowEval": false,
"allowDownloads": false,
"allowAllTabs": false,
"enableMutations": true
}