mirror of
https://github.com/obra/superpowers.git
synced 2026-06-11 05:09:05 +08:00
The companion server is reachable by any local browser tab (default loopback bind) and by any host that can route to it (remote --host bind). It served screens, files, and accepted event-injecting WebSocket connections with no authentication, so a malicious browser tab or a direct remote client could read brainstorm content or inject events that the agent reads as the user's input (prompt injection into a live session). Generate a per-session secret token, carry it in the served URL as ?key=, and mirror it into an HttpOnly SameSite=Strict per-port cookie on first load so same-origin subresources and the WebSocket handshake authenticate automatically. Every HTTP request and WebSocket upgrade now requires a valid key (query or cookie, constant-time compared); unauthenticated requests get a friendly 403 explaining they need the full URL. A secret authenticates the client uniformly across loopback, tunnel, and remote binds and defeats DNS rebinding, which a Host/Origin allowlist cannot. Also guard handleMessage against a null JSON payload that crashed the process. Tests: new auth.test.js (13 cases) covering the key on /, /files/*, and WS plus cookie bootstrap and the null-payload guard; server.test.js threads the key; ws-protocol.test.js + auth.test.js wired into npm test. Closes #1014 Refs #1110, #1553, #1504