Skip to content

brw v0.4.0

Choose a tag to compare

@revitteth revitteth released this 25 Jun 21:14
v0.4.0
69899fc

TL;DR: hardens the loopback surfaces (CSRF, DNS-rebinding, extension auth), makes the extension bridge survive high concurrency (backpressure, reconnect, per-tab serialization), and fixes snapshot-on-action and tab handling. Upgrading the daemon does not require reinstalling the extension.

Breaking changes

  1. Extension bridge caps concurrent operations at 6 by default. Beyond the cap, calls queue; past the operation deadline they return extension bridge busy, retry with backoff instead of running. Tune with --bridge-max-inflight (env BRW_BRIDGE_MAX_INFLIGHT), 0 disables. Concurrency was previously unbounded.
  2. HTTP control plane rejects cross-origin browser requests (CSRF) and, on a loopback bind, a non-allowlisted Host (DNS-rebinding). Loopback CLI, MCP, and curl send no browser Origin and are unaffected; a browser-based API consumer or a custom Host gets 403.
  3. Seamless bridge defaults: focus_tab no longer raises the OS window, and brw_open places tabs in a default brw tab group. Restore with --bridge-raise-window and --bridge-tab-group "".

Security

  • Per-launch extension bridge auth token: minted each start, persisted 0600 at ~/.brw/bridge-token, served only over loopback. Non-breaking by default (a wrong token is rejected; an older extension that sends no token still connects, logged once). Set BRW_BRIDGE_REQUIRE_TOKEN=1 to require it once every extension is reloaded.
  • navpolicy normalises hosts to ASCII/punycode, so a Unicode host and its xn-- form hit the same allow/deny rule (closes a blocklist-evasion gap).
  • Extension refuses every cookie CDP method and the whole Storage domain; cookies and passkeys cannot be read through brw even by a rogue local socket peer.
  • Non-browser (empty-Origin) websocket clients are rejected at the bridge.

Bridge resilience under load

  • Backpressure on the shared socket with a typed busy signal so callers can back off (see breaking #1).
  • Reconnect-aware: an RPC arriving during the MV3 service-worker reconnect gap waits for the socket instead of failing "not connected". Idempotent reads retry once on a transient drop; mutating ops never auto-retry.
  • Per-tab serialization: operations on one tab no longer interleave their CDP frames; distinct tabs still run in parallel.
  • WS frame write bound to its own deadline, so a cancelled or slow request can no longer tear down the shared socket.
  • /status reports inflight, queued, busy_drops, retries.

Reliability

  • snapshot:true on action tools now works across the MCP-server to bridge HTTP boundary (was dropped in the upstream-http topology).
  • WaitFor awaits a single in-page promise instead of polling a heavy condition, so concurrent waits no longer flood the debugger.
  • Tab enumeration via chrome.tabs.query across all window types (excludes only PWA/app and devtools).
  • Chrome stability: debugger detach on shutdown, graceful shutdown, profile guard, leak fixes.
  • JS alert/dialog auto-dismiss.

Tools and usability

  • New brw_navigate_to: navigate an existing tab to a URL, wait for load, return an observation.
  • snapshot:true on all action tools includes a full PageSnapshot in the result.
  • Dynamic ref disambiguation for sibling elements sharing a name.
  • brw_fill errors show the element tag and suggest brw_type; brw_wait_for accepts page_ready.