Version: impeccable@3.1.0 (also on HEAD)
File: .claude/skills/impeccable/scripts/live-server.mjs lines 388-414
return (req, res) => {
const url = new URL(req.url, `http://localhost:${state.port}`);
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); return; }
const p = url.pathname;
if (p === '/live.js') {
// ...
const body = assembleLiveBrowserScript({
token: state.token,
port: state.port,
// ...
});
Issue. Every other route under the live server (/source, /events, manual-edit endpoints) checks token === state.token and returns 401 on mismatch. But /live.js returns a JavaScript bundle with state.token embedded inline, without any auth check, and the handler sets Access-Control-Allow-Origin: * for all responses.
Impact. While the live server is running on the user's machine, any web page (or local process — a browser tab visiting an attacker-controlled site, a stray service worker, an iframe, etc.) that knows or probes the default localhost port can fetch /live.js, regex out the embedded token, and then make authenticated requests against /source, /events, and the manual-edit routes against the user's project. The token-gated authorization on the rest of the server is undermined.
The default port + the * CORS policy + the unauthenticated token-bearing script combine to make this a real local-network / local-browser attack surface, not a theoretical one. Mitigations like "localhost-only listen" don't help: the browser running on the same machine that hosts the live server is exactly the attack vector.
Fix options:
- Token-gate
/live.js too: require ?token=... on the script URL itself (the live mode's bootstrap can include the token in the script-tag src). Cleanest mitigation.
- Drop the token from the served script: serve a static-ish bootstrap that POSTs to a server-side handshake to acquire a per-session token. Larger refactor.
- Tighten CORS: replace
Access-Control-Allow-Origin: * with the live mode's known origin (the page being driven). Doesn't fix the same-origin case but reduces blast radius.
Surfaced by codex review against a real install. Wanted to file it so future installs aren't silently exposed.
Version: impeccable@3.1.0 (also on HEAD)
File:
.claude/skills/impeccable/scripts/live-server.mjslines 388-414Issue. Every other route under the live server (
/source,/events, manual-edit endpoints) checkstoken === state.tokenand returns 401 on mismatch. But/live.jsreturns a JavaScript bundle withstate.tokenembedded inline, without any auth check, and the handler setsAccess-Control-Allow-Origin: *for all responses.Impact. While the live server is running on the user's machine, any web page (or local process — a browser tab visiting an attacker-controlled site, a stray service worker, an
iframe, etc.) that knows or probes the default localhost port can fetch/live.js, regex out the embedded token, and then make authenticated requests against/source,/events, and the manual-edit routes against the user's project. The token-gated authorization on the rest of the server is undermined.The default port + the
*CORS policy + the unauthenticated token-bearing script combine to make this a real local-network / local-browser attack surface, not a theoretical one. Mitigations like "localhost-only listen" don't help: the browser running on the same machine that hosts the live server is exactly the attack vector.Fix options:
/live.jstoo: require?token=...on the script URL itself (the live mode's bootstrap can include the token in the script-tag src). Cleanest mitigation.Access-Control-Allow-Origin: *with the live mode's known origin (the page being driven). Doesn't fix the same-origin case but reduces blast radius.Surfaced by codex review against a real install. Wanted to file it so future installs aren't silently exposed.