Skip to content

Keep API tokens from loosening permission modes; mailbox browser-only; no pooled connections across network policies - #23

Merged
Jineggegg merged 2 commits into
mainfrom
fix/token-permission-modes
Oct 23, 2026
Merged

Jineggegg merged 2 commits into
mainfrom
fix/token-permission-modes

Conversation

@Jineggegg

Copy link
Copy Markdown
Owner

Why

A security review of the published 2.0.0-beta.4 found one medium and a few low issues. No secrets or personal data were found in the repository history, pull requests, releases or the release package.

Medium — an API token could take the person out of the loop. PATCH /api/sessions/:id refused a token that loosened the permission mode, but the same choice was accepted, unchecked, when a token

  • created a conversation (POST /api/sessions),
  • sent a message (POST /api/sessions/:id/messages),
  • scheduled a message (POST /api/deferred-messages),
  • created or changed an automation,
  • started a multi-agent task,
  • handed off.

In a project with Auto mode switched on, a write-scoped token could therefore start a run in which every tool call was allowed with nobody asked. Before this change, the new integration test showed a token creating an accept-edits session (201).

Threat considered: a leaked or member-held API token used to start unattended runs that skip human approval.

What changes

  • Permission modes: requireBrowserToLoosen (agents/token-modes.ts) is one check used by all seven entry points. Tokens may still choose Plan and Ask; Accept edits and Auto need a signed-in browser (session_required).
  • Mailbox: every mailbox route is sessionOnly. Before, a read-scoped token could list, read and download every connected mailbox, and create, change and delete drafts.
  • guardedRequest: uses agent: false. A keep-alive socket opened under a policy that allows private addresses could carry a later request whose policy does not, because no DNS check runs on reuse. The new unit test fails without the fix.
  • Installer:
    • it refuses redirects to plain http (--proto-redir '=https');
    • it now requires curl, because the wget fallback could not refuse such redirects.
  • Codex environment: Codex refuses extra variables with the CLOUD_HARNESS_ prefix as well as AGENT_STUDIO_, matching buildChildEnv.
  • Sample name: a neutral sample name replaces the previous one in the component gallery and a login test.
  • Docs and changelog: the guides and the changelog (2.0.0-beta.5 → Security) are updated.

Checks run locally

  • npm run typecheck passed.
  • npm run lint passed.
  • npm run test:unit: 3321 passed.
  • npm run test:integration: 1340 passed.
  • Build and npm run test:acceptance (before the rebase onto Add a visual product tour and custom-domain setup #22):
    • 433 of 434 passed;
    • the one failure was an EPIPE timing flake in AT-SEC-087;
    • that file passed on rerun.
  • gitleaks found no leaks in the new commits.

Not changed here (recorded for later)

  • Electron fuses and DevTools in packaged desktop builds.
  • The release job runs npm ci with install scripts on while it holds id-token: write.
  • The mini-app build sandbox mounts the whole project, .git included, as writable.
  • Server-wide single browser session and build slot (one user can hold them).
  • Control characters in Windows-companion type actions are not shown escaped in the approvals.
  • The run bridge MCP config lives in /tmp, readable by the agent's own tools.

🤖 Generated with Claude Code

Jineggegg and others added 2 commits October 23, 2026 19:26
…ections

A token could already not PATCH a conversation into Accept edits or Auto,
but it could choose those modes when it created a conversation, sent or
scheduled a message, created or changed an automation, started a task or
handed off. With Auto mode switched on for the project that ran every tool
call with nobody asked. One check, requireBrowserToLoosen, now guards all of
those entry points; Plan and Ask stay open to tokens.

Also:
- Mailbox accounts, messages, attachments and drafts are session-only: a
  read-scoped token could read every connected mailbox.
- guardedRequest opens a fresh connection per request, so a keep-alive
  socket opened under a policy that allows private addresses cannot carry
  a later request whose policy does not (no DNS check runs on reuse).
- The installer refuses redirects to plain http.
- Codex refuses extra CLOUD_HARNESS_ variables like AGENT_STUDIO_ ones.
- A neutral sample name in the component gallery and a login test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
wget follows a redirect to plain http and has no option to refuse it, so the
fallback undid the redirect check. The mailbox's local-model list joins the
other mailbox routes so that the guide's "every mailbox route" holds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Jineggegg
Jineggegg merged commit 37fbea0 into main Oct 23, 2026
20 checks passed
@Jineggegg
Jineggegg deleted the fix/token-permission-modes branch October 23, 2026 18:37
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.

1 participant