You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The README says to point a framework's cdp_url at the URL the bridge prints. The popular Node clients cannot complete that connection today: the gate refuses the methods they issue during the attach handshake. This affects Puppeteer, Playwright, and the Playwright-based agents (browser-use, Stagehand).
Not a security bug (the gate is doing its job) — a usability gap between what the README invites and what the allowlist permits.
Repro
Start any bridge (the demo.mjs setup is enough), then point a stock client at bridge.url:
Protocol error (Browser.getVersion): method_not_allowed:
Browser.getVersion is not on the bridge allowlist
Verified with puppeteer-core@23 and playwright-core@1.48 against a real Chromium.
Root cause
Two layers, and the second is the hard one:
Browser.getVersion is not in ALLOWED_METHODS (cdp-policy.ts). Both clients call it first thing on connect.
Even with that added, both drive target discovery with Target.setAutoAttach and Target.setDiscoverTargets, which are in NEVER_ALLOWEDby design — the module doc is explicit that re-attaching to Chromium outside the gate makes the no-plaintext invariant moot.
So this is not a one-line allowlist change. Supporting a stock framework client means the proxy answering the discovery handshake itself (synthesizing Browser.getVersion, and presenting only the client's own gated targets in response to auto-attach/discovery) rather than forwarding those commands to Chromium.
Proxy the handshake: make the proxy respond to Browser.getVersion and the target-discovery commands locally, scoped to the client's assigned context, so Puppeteer/Playwright believe they attached to a normal browser while still only ever seeing gated targets. This is what unlocks browser-use and Stagehand, which are the frameworks people will actually bring. Bigger change, needs its own adversarial coverage (a synthesized discovery reply must not become a way back to an ungated target).
Context
Found while writing the examples in #1. The examples/README.md there documents the current state so integrators do not lose time to it; this issue is to track the underlying decision (document vs. proxy the handshake).
Summary
The README says to point a framework's
cdp_urlat the URL the bridge prints. The popular Node clients cannot complete that connection today: the gate refuses the methods they issue during the attach handshake. This affects Puppeteer, Playwright, and the Playwright-based agents (browser-use, Stagehand).Not a security bug (the gate is doing its job) — a usability gap between what the README invites and what the allowlist permits.
Repro
Start any bridge (the
demo.mjssetup is enough), then point a stock client atbridge.url:Both fail immediately:
Verified with
puppeteer-core@23andplaywright-core@1.48against a real Chromium.Root cause
Two layers, and the second is the hard one:
Browser.getVersionis not inALLOWED_METHODS(cdp-policy.ts). Both clients call it first thing on connect.Target.setAutoAttachandTarget.setDiscoverTargets, which are inNEVER_ALLOWEDby design — the module doc is explicit that re-attaching to Chromium outside the gate makes the no-plaintext invariant moot.So this is not a one-line allowlist change. Supporting a stock framework client means the proxy answering the discovery handshake itself (synthesizing
Browser.getVersion, and presenting only the client's own gated targets in response to auto-attach/discovery) rather than forwarding those commands to Chromium.Options
examples/agent.mjsdoes, and use the MCP tools for anything touching a credential. Cheapest, and honest about the current surface.Browser.getVersionand the target-discovery commands locally, scoped to the client's assigned context, so Puppeteer/Playwright believe they attached to a normal browser while still only ever seeing gated targets. This is what unlocks browser-use and Stagehand, which are the frameworks people will actually bring. Bigger change, needs its own adversarial coverage (a synthesized discovery reply must not become a way back to an ungated target).Context
Found while writing the examples in #1. The
examples/README.mdthere documents the current state so integrators do not lose time to it; this issue is to track the underlying decision (document vs. proxy the handshake).