Skip to content

Pin local daemon WS server to the first connecting extension - #274

Open
carfeii wants to merge 1 commit into
Tencent:mainfrom
carfeii:fix/pin-local-daemon-to-first-extension-origin
Open

carfeii wants to merge 1 commit into
Tencent:mainfrom
carfeii:fix/pin-local-daemon-to-first-extension-origin

Conversation

@carfeii

@carfeii carfeii commented Sep 17, 2026

Copy link
Copy Markdown

Fixes #273.

Adds ExtensionPinStore (mirroring the existing AuthorizationStore atomic-write pattern already used for remote-mode device grants in daemon/remote/authorization.rs) and wires it into handle_connection: the first extension origin to complete a WS upgrade is pinned and persisted to ~/.bsk/extension-pin.json, and any other origin is rejected from then on with a policy close. origin_allowed() itself is unchanged (it still validates the origin's shape, as before) since this fix layers identity pinning on top of it rather than replacing it.

Includes a live end-to-end test (crates/bsk-cli/tests/extension_pin_ws.rs) that binds a real WsServer to a real local port and performs real WebSocket handshakes with two distinct extension origins, confirming the first pins and the second is rejected while the first can still reconnect. All 151 pre-existing daemon:: unit tests, including the five origin_allowlist_* tests covering the unchanged shape check, still pass.

origin_allowed() only checked that a connecting page's Origin header
was shaped like a Chrome extension origin (chrome-extension:// plus
32 lowercase a-p characters), never which specific extension it was.
Every installed extension's origin has exactly this shape, so any
other extension in the same browser profile was accepted identically
to BrowserSkill's own extension, gaining full control of the daemon
and, through it, of the user's real, already-logged-in browser.

Adds ExtensionPinStore (mirroring the existing AuthorizationStore
atomic-write pattern used for remote-mode device grants) and wires it
into handle_connection: the first extension origin to complete a WS
upgrade is pinned and persisted, and any other origin is rejected
from then on. Includes a live end-to-end test against the real WS
server.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local WebSocket daemon accepts commands from any browser extension, not just BrowserSkill's own

1 participant