From 0c51c4a4601115a8788b9fa78c7342af7c310ced Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Mon, 27 Apr 2026 23:51:06 -0700 Subject: [PATCH] docs: bump tunnel allowlist count 17 -> 26 in CLAUDE.md and REMOTE_BROWSER_ACCESS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both docs already named the 9 new commands as remote-accessible (the operator guide's per-command sections at lines 86-119 and 168, plus cli.ts:546-586's instruction blocks). The allowlist count was the only place the drift was visible. Also corrected REMOTE_BROWSER_ACCESS.md's denied-commands list: 'eval' is in the allowlist, not the denied list — prior doc was wrong. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 2 +- docs/REMOTE_BROWSER_ACCESS.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 2e5ae567..cd08caf4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -258,7 +258,7 @@ through `POST /pty-session` only. **Transport-layer security** (v1.6.0.0+). When `pair-agent` starts an ngrok tunnel, the daemon binds two HTTP listeners: a local listener (127.0.0.1, full command surface, never forwarded) and a tunnel listener (locked allowlist: `/connect`, -`/command` with a scoped token + 17-command browser-driving allowlist, +`/command` with a scoped token + 26-command browser-driving allowlist, `/sidebar-chat`). ngrok forwards only the tunnel port. Root tokens over the tunnel return 403. SSE endpoints use a 30-minute HttpOnly `gstack_sse` cookie minted via `POST /sse-session` (never valid against `/command`). Tunnel-surface rejections go diff --git a/docs/REMOTE_BROWSER_ACCESS.md b/docs/REMOTE_BROWSER_ACCESS.md index e7386ffa..88dc30bb 100644 --- a/docs/REMOTE_BROWSER_ACCESS.md +++ b/docs/REMOTE_BROWSER_ACCESS.md @@ -32,7 +32,7 @@ GStack Browser Server Any AI agent The daemon binds two HTTP sockets. The **local listener** serves the full command surface to 127.0.0.1 only and is never forwarded. The **tunnel listener** is bound lazily on `/tunnel/start` (and torn down on `/tunnel/stop`) with a locked path allowlist. ngrok forwards only the tunnel port. -A caller who stumbles onto your ngrok URL cannot reach `/health`, `/cookie-picker`, `/inspector/*`, or `/welcome` — those paths don't exist on that TCP socket. Root tokens sent over the tunnel get 403. The tunnel listener accepts only `/connect`, `/command` (with a scoped token + the 17-command browser-driving allowlist), and `/sidebar-chat`. +A caller who stumbles onto your ngrok URL cannot reach `/health`, `/cookie-picker`, `/inspector/*`, or `/welcome` — those paths don't exist on that TCP socket. Root tokens sent over the tunnel get 403. The tunnel listener accepts only `/connect`, `/command` (with a scoped token + the 26-command browser-driving allowlist), and `/sidebar-chat`. See [ARCHITECTURE.md](../ARCHITECTURE.md#dual-listener-tunnel-architecture-v1600) for the full endpoint table. @@ -165,7 +165,7 @@ Each agent owns the tabs it creates. Rules: ## Security Model - **Physical port separation.** Local listener and tunnel listener are separate TCP sockets. ngrok only forwards the tunnel port. Tunnel callers cannot reach bootstrap endpoints at all (404, wrong port). -- **Tunnel command allowlist.** `/command` over the tunnel only accepts 17 browser-driving commands (goto, click, fill, snapshot, text, etc.). Server-management commands (tunnel, pair, token, useragent, eval, js) are denied on the tunnel. +- **Tunnel command allowlist.** `/command` over the tunnel only accepts 26 browser-driving commands (goto, click, fill, snapshot, text, newtab, tabs, back, forward, reload, closetab, etc.). Server-management commands (tunnel, pair, token, useragent, js) are denied on the tunnel. - **Root token is tunnel-blocked.** A request bearing the root token over the tunnel listener returns 403 with a pairing hint. Only scoped session tokens work over the tunnel. - **Setup keys** expire in 5 minutes and can only be used once. - **Session tokens** expire in 24 hours (configurable).