Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Why crossmem bridge does not use Chrome DevTools Protocol

The incident

On a developer workstation, a suspicious process (PID 73079) spawned from a Claude shell snapshot executed the following sequence:

  1. sleep 2400 (wait for Chrome to settle)
  2. Connect to ws://localhost:9222 (Chrome DevTools Protocol)
  3. Runtime.evaluateClerk.session.getToken() to steal the active session token
  4. POST the stolen token to an external API (teaching.monster)

Root cause: a dev tool had launched Chrome with --remote-debugging-port=9222. This single flag exposes every open tab, every origin, every cookie on a localhost WebSocket with zero authentication. Any local process—malicious or not—can connect and run arbitrary JavaScript in the context of any page the user has open. CDP is a debugger; it trusts the caller completely.

What crossmem bridge does differently

crossmem bridge is a Manifest V3 Chrome extension that communicates with local agents over a WebSocket on localhost:7600. The design differs from CDP in several concrete ways:

  • No --remote-debugging-port. The user’s Chrome launches normally. There is no app-wide debug backdoor to connect to.
  • User-installed extension with Chrome’s permission UI. The user explicitly grants the extension host permissions. CDP requires no user consent at all; whatever launched Chrome with the flag decides.
  • Whitelisted action set. The bridge accepts a fixed set of named actions: navigate, click, type, extract, screenshot, summarize, tab_info, wait, ping. There is no generic “evaluate arbitrary JS” verb. An attacker who connects to :7600 can click buttons and read extracted text, but cannot call Clerk.session.getToken() or Network.getAllCookies.
  • Real Chrome profile, no spoofing. The extension runs inside the user’s actual Chrome profile—no --user-data-dir to a throwaway directory, no Chrome for Testing with broken Keychain integration.

Threat model comparison

Attack surfaceCDP (:9222)crossmem bridge (:7600)
Arbitrary JS on any originRuntime.evaluate — yesNo eval verb — no
Dump all cookiesNetwork.getAllCookies — yesNo such action — no
Read/modify DOMFull DOM accessOnly via named actions (click, extract)
AuthenticationNoneNone (same weakness — see below)
User consentNone; whoever launched Chrome decidesChrome extension install prompt

The PID 73079 attack required exactly two CDP primitives: Runtime.evaluate and network access. Neither exists in the crossmem bridge action vocabulary.

What this design does NOT protect against

Honesty matters more than marketing. crossmem bridge has real limitations:

  • localhost:7600 is unauthenticated, same as CDP on :9222. Any local process can connect. The attack surface is smaller (no eval, no cookie dump), but the network posture is identical.
  • chrome.scripting.executeScript is arbitrary JS under the hood. The bridge currently uses it to implement actions like extract and click. If a future action handler passes attacker-controlled input (selectors, payloads) into executeScript without sanitization, the constrained action set becomes a confused deputy.
  • Supply-chain attack on the extension itself. A malicious MV3 update pushed to the Chrome Web Store bypasses every architectural constraint. The extension IS the trust boundary.
  • Planned hardening (not yet implemented):
    • Per-request auth token (shared secret between agent and extension)
    • Unix domain socket instead of TCP (removes network-reachable surface)
    • Strict input validation on action parameters

Takeaway

The lesson from PID 73079 is not “use crossmem bridge instead of CDP.” It is: dev automation tooling should not default to opening an app-wide debug backdoor.

CDP is a debugger protocol. It was designed for DevTools, not for agent orchestration. When you expose it on localhost, you hand every local process— including ones you didn’t launch—full control over every tab in the browser.

crossmem bridge chose a constrained, consent-gated channel: a user-installed extension exposing a fixed action vocabulary over a local WebSocket. This is a design choice that reduces the blast radius of local-process compromise. It is not magic, and it is not complete. But it means PID 73079’s exact attack vector—connect, eval, exfiltrate—does not work.