Skip to content

fix(cli): stop a configured sandbox from bypassing approval remotely - #1835

Open
ethicnology-agent wants to merge 2 commits into
slopus:mainfrom
ethicnology-agent:fix/cli-sandbox-does-not-bypass-approval
Open

ethicnology-agent wants to merge 2 commits into
slopus:mainfrom
ethicnology-agent:fix/cli-sandbox-does-not-bypass-approval

Conversation

@ethicnology-agent

Copy link
Copy Markdown

Fixes the first defect reported in #1830.

Problem

runClaude derives the permission mode from sandbox configuration rather than from a sandbox that exists:

const sandboxEnabled = Boolean(sandboxConfig?.enabled);
const initialPermissionMode = applySandboxPermissionPolicy(
    resolveInitialClaudePermissionMode(options.permissionMode, options.claudeArgs),
    sandboxEnabled,
);

applySandboxPermissionPolicy rewrites the mode to bypassPermissions unconditionally, before any execution path has been chosen, and resolveRemoteClaudePermissionMode re-applies it to every incoming message.

claudeLocal is the only Claude path that calls initializeSandbox (claudeLocal.ts:283), and it appends --dangerously-skip-permissions itself inside the branch where that call succeeded — it even falls back to no sandbox and no flag on Windows. The remote path never initializes a sandbox at all.

The result is that turning the sandbox on removes every approval prompt from remote sessions while nothing confines them. Enabling the feature makes a remote session strictly less safe than leaving it off, which is the opposite of what the setting offers. The app meanwhile displays "Sandbox: Enabled".

Codex in this repository already gets this right: codexAppServerClient sets sandboxEnabled = false, then true only after initializeSandbox and wrapForMcpTransport both succeed, and runCodex reads that observed value. This aligns Claude with the same rule.

What this changes

Read the commits in order:

  1. fix(cli): stop a configured sandbox from bypassing approval remotely — the behaviour change. runClaude uses resolveInitialClaudePermissionMode directly, and resolveRemoteClaudePermissionMode no longer takes a sandbox flag. Three cases replace the one that encoded the old behaviour: an explicit plan request stays plan, default stays default, and the existing guard against an ambient default downgrading a bypassing session still holds.
  2. refactor(cli): drop the now-unused sandbox permission policy helper — removes applySandboxPermissionPolicy and the dead parameter. No behaviour change; separated so the first commit stays small enough to judge.

tsc --noEmit is clean and the CLI unit suite passes 993/993.

What this deliberately does not change

  • The local path keeps its current trade-off. claudeLocal still adds --dangerously-skip-permissions once the sandbox is genuinely in place. That is a defensible bargain and this PR does not relitigate it.
  • The dangerouslySkipPermissions metadata flag still includes sandboxEnabled. After this change it over-reports danger for remote sessions rather than under-reporting it, which is the safe direction; making it exact needs the local/remote distinction, and the run mode can change at runtime (runClaude.ts:793, :952). Worth a follow-up, not worth widening this diff.

Caveats, stated plainly

I could not exercise the runtime local↔remote mode switch, so that path is reasoned about from source rather than observed. If you would rather a configured sandbox refuse to start a remote session instead of falling back to prompting, say so — that is a one-line change to the same place, and it is your product call, not mine.

runClaude derived the permission mode from sandbox configuration rather
than from a sandbox that exists. applySandboxPermissionPolicy rewrote the
mode to bypassPermissions whenever settings.sandboxConfig.enabled was set,
before any execution path had been chosen, and resolveRemoteClaudePermissionMode
re-applied it to every incoming message.

claudeLocal is the only Claude path that calls initializeSandbox, and it
appends --dangerously-skip-permissions itself, inside the branch where the
sandbox has actually been put in place. The remote path never initializes
one. Turning the sandbox on therefore removed every approval prompt from
remote sessions while nothing confined them, which is the opposite of what
the setting offers.

Codex already binds its auto-approval to observed state: codexAppServerClient
sets sandboxEnabled false, then true only after initializeSandbox and
wrapForMcpTransport both succeed. This aligns Claude with that.

The regression that encoded the old behaviour is removed and replaced by
cases asserting that an explicit plan request stays plan, while the existing
guard against an ambient default downgrading a bypassing session still holds.
applySandboxPermissionPolicy has no caller since the previous commit, and
resolveRemoteClaudePermissionMode's sandboxEnabled parameter is no longer
read. Remove both, with the tests that covered the helper directly.

No behaviour change.
@ethicnology-agent
ethicnology-agent force-pushed the fix/cli-sandbox-does-not-bypass-approval branch from f516c7a to 9aa6d02 Compare October 1, 2026 19:02
@ethicnology-agent

Copy link
Copy Markdown
Author

Rebased onto current main (4cf54d1). Clean rebase, diff unchanged.

This branch has not been deployed

No deployments
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.

2 participants