Both /live and /channel validate the request Origin against local loopback origins (127.0.0.1, localhost, [::1]) and require a cryptographic pairing bearer (vbx_...) for non-local peers. Because browsers enforce immutable Origin headers on WebSocket handshakes, this closes Cross-Site WebSocket Hijacking (CSWSH) from external web pages.
This document analyzes the local loopback process boundary: what a non-browser process running on the same machine can do, why embedding a token inside unauthenticated HTML does not add security, and how the opt-in bootstrap session gate (VOICEBOX_LOOPBACK_AUTH=1) works.
Over loopback TCP (127.0.0.1), the operating system kernel does not attach browser identity to a socket. Any process running on the same machine (under the same user or a shared network namespace) can open a TCP socket and send Origin: http://127.0.0.1:8787.
Injecting an ephemeral session token into openly served HTML (for example, <meta name="voicebox-page-token" content="...">) does not prevent local scripts from connecting:
To distinguish the authorized user’s browser session from an unprivileged local process, the initial credential must be delivered out-of-band rather than embedded in unauthenticated HTML.
Established by tools such as Jupyter Notebook and VS Code Server (code-server):
VOICEBOX_LOOPBACK_AUTH=1 is set, the server does not serve HTML or API routes without an authenticated session.http://127.0.0.1:8787/?bootstrap=<ticket>) to stdout (or mints one on demand via POST /api/bootstrap authenticated with x-voicebox-host-token)./?bootstrap=<ticket> redeems the ticket once, sets an HttpOnly, SameSite=Strict session cookie (vb_session), and answers 303 to the same route with the ticket removed — so the address bar is left holding the plain page a refresh can re-request./channel, /live) requests require either the session cookie or x-voicebox-host-token.crypto.subtle.generateKey(..., false, ["sign", "verify"])), stores it in IndexedDB, and displays a pairing code..host-token.| Property | Default Baseline (Origin Check) |
Option A: Bootstrap Ticket (VOICEBOX_LOOPBACK_AUTH=1) |
Option B: WebCrypto Pairing |
|---|---|---|---|
| Cross-site browser attacks (CSWSH) | Blocked (Origin header) |
Blocked (Cookie + Origin) |
Blocked (Key signature) |
| Other OS users / containers on shared loopback | Unblocked | Blocked (.host-token mode 0600) |
Blocked (Console pairing) |
| Same-UID local scripts | Unblocked | Unblocked (can read .host-token) |
Blocked (Non-extractable key) |
Direct URL launch (http://localhost:8787) |
Yes (zero friction) | Requires bootstrap URL on first load | Requires one-time console pairing |
| Failure recovery | Reload page | Open printed URL or call POST /api/bootstrap |
Re-pair if IndexedDB is cleared |
Voicebox implements Option A (Host-Token Bootstrap Ticket) as an opt-in security gate (VOICEBOX_LOOPBACK_AUTH=1), while keeping the zero-friction Origin-validated baseline as the default for single-user workstations:
0600 .host-token boundary already used for /api/root, /api/pair, and extension admission.18-loopback-session-auth.md and tests/loopback-auth.test.mjs.