Skip to content

Claude coding sandbox settings

Decisions about Claude Code's own Bash sandbox on Linux that depend on the host and the installed Claude version, kept apart from the launch options in session-launch.ts.

procEnvironMitigation decides whether a coding launch re-allows the per-process environ files with /proc/[0-9]*/environ. Claude expands its built-in denial of them into one bind per host process, and bwrap fails the command when a process exits in the meantime. With the allow, a run with Claude 2.1.302 went from 531 such arguments to one. It is a mitigation: a smaller window remains.

The allow is withheld, never refused, unless all of these hold: Linux outside WSL (Claude's own test: microsoft or wsl in the lowercased /proc/version, so 6.12.10-WSL2-custom counts); a gateway Connection whose base URL is not Claude's first-party host (the accounts Claude fetches remote managed settings for are subscription and API-key accounts on that host); no administrator Claude settings file or drop-in (existence only, nothing parsed); and a Claude version from 2.1.302 up to, not including, 2.2.0. A managed policy outranks the inline enableWeakerNestedSandbox: false the launch pins beside the allow, and that setting would let the allow expose other processes' environments, so any policy source withholds. A withheld launch keeps today's settings and logs one line (maia.claude.sandbox_mitigation_skipped).

makeExecutableVersionReader reads the version out of the approved binary's bytes and never runs them. One pass hashes the file and scans for the version, and the version counts only when the hash equals the approved digest. One deadline covers the whole lookup, the stat and the wait for the lock included. Launches that start together share one read and its outcome, a failure included; a later launch tries again, since failures are not remembered. The answer stays in memory by digest and file identity. A format it does not recognize gives no version, and the launch keeps today's settings.

Residual risks

  • The policy check runs before the launch. An administrator who installs policy in between invalidates it, and no check closes that gap.
  • The approved range, 2.1.302 up to 2.2.0, is a compatibility assumption beyond the 2.1.302 evidence. Widen it only after a real canary run.
  • The allowance trusts the gateway. Claude 2.1.302 decides in this order whether an account may fetch remote managed settings: a hermetic remote session is ineligible; an entrypoint that sets its own rule follows it; a host-credential gateway slot is eligible only when pinned; any CLAUDE_CODE_USE_* provider is ineligible; a base URL that is not api.anthropic.com is ineligible (custom_base_url) unless _CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL is set or the gateway's client data document says assumesFirstPartyBaseUrl; only then do the subscription tier and API-key checks apply. A gateway that serves that client data document can therefore make its own Connection eligible, and a remote policy outranks the inline enableWeakerNestedSandbox: false. The gateway already sees every prompt, the token and the account, so Maia accepts this as a trust assumption and does not try to detect it.
  • This lowers the chance of the race and does not remove it.

Tests use an in-memory file system for the kernel banner, the administrator files and the binary, and check each condition on its own.

Imported from Maia OS docs at a2175bb