This repository is a local-only prototype. It is not production-ready unless you understand and configure the hardening controls described here.
- The broker must bind only to loopback hosts.
- The extension must connect only to loopback
ws://bridge URLs. - There are no default tokens. Operators must generate and configure a high-entropy value in
CHROME_BROWSER_CONTROL_TOKEN. - The extension exposes tabs and page actions only for allowed origins configured in the popup. Explicit entries such as
https://example.comare supported, and*enables all normalhttp://andhttps://web pages while still blockingchrome://,file://, extension pages, and other non-web schemes. - Allowed-origin checks run in the extension background before content actions, tab claims, and screenshots.
- Tab claims are advisory routing state by default. Use
claim_tab({ exclusive: true, ttlMs?, owner? })for fail-fast coordination leases across parallel agents; leases expire by TTL and do not create browser locks. They do not close user tabs. - Password-like and OTP fields are blocked by
typeunless the caller passesforce=true. - Structured extraction tools are bounded.
includeHtmlredacts password/OTP/hidden-token attribute values and marks sensitive items; it should still be treated as untrusted page content. Raw JavaScript evaluation, cookies, localStorage, sessionStorage, browser history, bookmarks, downloads, and request headers are intentionally out of scope. Response headers andSet-Cookieare never exposed at any tier. - Response bodies are readable only through the optional CDP tier, and only for origins explicitly listed in the extension popup's body-capture allowlist. That list is deny-by-default and does not accept
*. Restricted categories (banking, wallet, password manager) are refused even when explicitly listed. Bodies are fetched on demand one request at a time and are never buffered. Token-shaped fields receive best-effort masking, which is not a guarantee — treat any response body as if it contains credentials. - Every response-body read is recorded to an append-only metadata log under
~/.chrome-browser-control/(timestamp, origin, URL, method, status, size). Body content is never written to that log. - The CDP tier may send only an enumerated list of protocol methods, enforced in code.
Fetch,Network.setRequestInterception,Network.continueInterceptedRequest, andRuntime.evaluateare forbidden: this project reads traffic and never modifies it. Extending that list is a security posture change. - Visible screenshots may activate an inactive target tab because Chrome MV3 captures the visible tab in a window. Chrome requires
<all_urls>oractiveTabforcaptureVisibleTab; this project requests optional<all_urls>as a host permission only for wildcard screenshot support. The extension background still rejects non-http(s) and unapproved URLs before capture. - The broker can optionally require
CHROME_BROWSER_CONTROL_EXTENSION_IDto pin one installed extension. - Non-loopback binding is unsupported.
- Trusted CDP input requires the
debuggerpermission in the manifest. Chrome shows a one-time warning when the unpacked extension is loaded. The extension always holds debugger capability; Chrome does not allow revoking a required permission without uninstalling. The tier itself stays off until the popupenableCdpcheckbox is on. Attach then requires a claimed tab and an allowed origin. Commands are constrained toInput.dispatchMouseEvent,Input.dispatchKeyEvent,Network.enable,Network.disable, andNetwork.getResponseBody. The socket fails closed on service-worker suspension, navigation to a disallowed origin, DevTools eviction, the popup toggle turning off, and Allowed Origins changes that leave the tab outside the list. Hydration never resumes a stored attachment fromgetTargets()attached: true, because that flag has no owner.Fetch.*,Network.setRequestInterception,Network.continueInterceptedRequest, andRuntime.evaluateare forbidden, not merely unimplemented. The MCP adapter does not open a raw CDP socket.
Please open a private security advisory on GitHub when available, or contact the repository owner through their GitHub profile.
Do not include live pairing tokens, private config files, browser logs, or personal filesystem paths in public reports.