allowUnsandboxedCommands: false does not cover the ! shell-mode prompt (2026)
Claude Code v2.1.260 narrowed strict sandbox mode so it no longer covers commands you type at the ! prompt. Anthropic documents two exceptions the changelog never mentions, and the variable that closes the gap is filed under credential scrubbing.
On this page
Quick answer (September 2026)
Setting "allowUnsandboxedCommands": false puts Claude Code into what the /sandbox panel calls Strict sandbox mode. As of v2.1.260, released 3 September 2026, that mode covers the commands Claude runs and no longer covers the commands you type yourself at the ! prompt. Anthropic's sandboxing reference states the change directly: "Before v2.1.260, strict sandbox mode sandboxed shell-mode commands in every session."
There are exactly two documented exceptions where your own typed commands are still sandboxed: a background session, and a Linux session with CLAUDE_CODE_SUBPROCESS_ENV_SCRUB set. Neither appears in the changelog line that announced the change.
If you set this flag for policy reasons, the flag still does its job. If you set it believing it made the whole session incapable of touching your machine unsupervised, that belief was correct before 3 September 2026 and is not correct now on an interactive desktop session.
The setting, and the two words that carry it
sandbox.allowUnsandboxedCommands has been around since v2.0.30 (published 30 October 2025). The changelog introduced it as a policy control: "Added allowUnsandboxedCommands sandbox setting to disable the dangerouslyDisableSandbox escape hatch at policy level."
The mechanism is narrow and well documented. When a sandboxed command fails because it touched a denied path or host, Claude may retry it with a dangerouslyDisableSandbox parameter, which runs it outside the sandbox under the normal permission flow. Setting the flag to false makes Claude Code ignore that parameter entirely.
Here is the settings reference on the false value, verbatim:
Settings reference, verbatim: "Claude Code ignores that parameter, so every command Claude runs is sandboxed or appears in excludedCommands."
And the sandboxing page:
Sandboxing reference, verbatim: "With the escape hatch disabled, Claude Code ignores the dangerouslyDisableSandbox parameter, and every command Claude runs must run sandboxed unless you've listed it in excludedCommands."
Read those two sentences again and notice that both of them say "every command Claude runs". Not every command in the session. The qualifier is three words long, it sits in the middle of a sentence, and it is the entire boundary of the feature. Before v2.1.260 the distinction did not matter in practice, because shell-mode commands were sandboxed too. Now it is the whole story.
What actually changed in 2.1.260
The changelog entry is one line:
Claude Code CHANGELOG, v2.1.260, verbatim: "Changed commands typed at the ! bash-mode prompt to run outside the sandbox even when strict sandbox mode (sandbox.allowUnsandboxedCommands: false) is on, like typing into your own terminal."
That line is accurate and it is filed under Changed, not Fixed, so the behaviour moved rather than being repaired. The docs confirm the direction without ambiguity, which is unusual and worth crediting: most vendors document what a product does now and leave you to infer what it used to do.
Sandboxing reference, verbatim: "Before v2.1.260, strict sandbox mode sandboxed shell-mode commands in every session."
So this is a deliberate narrowing of a security control, announced by the vendor, documented by the vendor, with the prior behaviour stated by the vendor. The rationale is in the changelog line itself: ! is meant to feel "like typing into your own terminal", and a shell prompt that silently refuses to reach your own home directory is a confusing shell prompt.
Reasonable design call. It is still a narrowing, and if you wrote a policy against the old behaviour, your policy now means something smaller than it did.
The full timeline, dated from the registry
Blog datelines drift and changelog headings carry no dates, so these are npm publish timestamps for @anthropic-ai/claude-code read directly from the registry.
Scroll to see more
| Version | Published | What happened |
|---|---|---|
| 2.0.30 | 30 October 2025 | allowUnsandboxedCommands added, described as disabling the escape hatch "at policy level" |
| 2.1.83 | 24 March 2026 | CLAUDE_CODE_SUBPROCESS_ENV_SCRUB added, purely as a credential scrubber |
| 2.1.98 | 9 April 2026 | Same variable gains Linux PID namespace isolation for Bash subprocesses |
| 2.1.260 | 3 September 2026 | Strict sandbox mode stops covering shell-mode commands in interactive sessions |
That is 309 days between the setting shipping and the day its scope narrowed, and 162 days between the scrub variable shipping for one reason and becoming the documented remedy for a different one. Anything written about this setting before September 2026 describes the wider behaviour, and almost all of the writing about it is from before September 2026.
The two exceptions the changelog does not mention
This is the part that is only on the docs page. The sandboxing reference lists the change and then immediately qualifies it twice:
Sandboxing reference, verbatim: "Strict sandbox mode applies to the commands Claude runs. Commands you type yourself at the ! shell-mode prompt run outside the sandbox unless the session is one of these: A background session: strict sandbox mode covers shell-mode commands too. A Linux session with CLAUDE_CODE_SUBPROCESS_ENV_SCRUB set: every command runs sandboxed, shell-mode commands included."
Count what the one-line changelog entry left out: a session type and an environment variable, either of which fully restores the old behaviour. A reader who only saw the release note would conclude the hole is unconditional. It is not. It is conditional on three things at once: an interactive session, and either a non-Linux platform or Linux without that variable set.
That gives a small decision table, and it is worth having in front of you before you change anything:
Scroll to see more
| Session | CLAUDE_CODE_SUBPROCESS_ENV_SCRUB | Are your ! commands sandboxed? |
|---|---|---|
| Interactive, macOS | not applicable | No |
| Interactive, Linux or WSL2 | unset | No |
| Interactive, Linux or WSL2 | set | Yes |
| Background session, any platform | either | Yes |
The macOS row is the one to sit with. The variable's sandboxing effect is documented as Linux-only, so on a Mac there is no documented way to put shell-mode commands back inside the sandbox while keeping an interactive session.
The variable that closes the hole is filed under credentials
Here is the finding that took the longest to pin down, and it is a documentation-shape problem rather than a product problem.
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB arrived in v2.1.83 (24 March 2026) with a purpose that has nothing to do with sandboxing:
CHANGELOG v2.1.83, verbatim: "Added CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 to strip Anthropic and cloud provider credentials from subprocess environments (Bash tool, hooks, MCP stdio servers)."
Two weeks later, in v2.1.98 (9 April 2026), it quietly acquired a second job:
CHANGELOG v2.1.98, verbatim: "Added subprocess sandboxing with PID namespace isolation on Linux when CLAUDE_CODE_SUBPROCESS_ENV_SCRUB is set."
So a variable named after environment scrubbing became a sandboxing lever, and five months later became the only documented way to keep your own typed commands inside the sandbox on Linux.
Now go to the page you would actually reach for. Anthropic's environment variables reference gives the variable its own entry, and that entry reads, in full: credential stripping, then the PID namespace note, then a caveat that ps, pgrep and kill stop seeing host processes, then a note about claude-code-action. It does not mention strict sandbox mode. It does not mention shell mode.
I measured the page rather than eyeballing it. Across 121,080 characters of visible text on the environment variables reference, the string sandbox occurs twice, case-insensitively, and both occurrences are inside the CLAUDE_CODE_TMPDIR entry, which is about temporary directory paths. Zero of them are in the CLAUDE_CODE_SUBPROCESS_ENV_SCRUB entry.
The variable also appears a second time on that page, inside the description of a different variable (CLAUDE_CODE_SCRIPT_CAPS, which only applies when the scrub variable is set). That is normal cross-referencing, and it is worth flagging because it means a naive count of "how many times is this variable discussed" over-reports by one.
The practical consequence: if you are on Linux, hardening a policy, and you look up CLAUDE_CODE_SUBPROCESS_ENV_SCRUB to decide whether to set it, the reference page will tell you it protects credentials and breaks ps. It will not tell you it is the switch that closes your shell-mode sandbox gap.
A terminology split that breaks the obvious search
The changelog calls it the ! bash-mode prompt. The docs call it the ! shell-mode prompt.
Measured across the three relevant reference pages, totalling 469,305 characters of visible text:
Scroll to see more
| Page | "bash mode" / "bash-mode" | "shell mode" / "shell-mode" |
|---|---|---|
| Sandboxing | 0 | 5 |
| Settings reference | 0 | 2 |
| Environment variables | 0 | 0 |
Zero on all three for the changelog's own term. So the natural move after reading the release note, searching the documentation for "bash mode", returns nothing on every page that could answer your question. This is a small thing that costs real time, and it is the reason the exception list above is not widely known. It is the same class of problem as a setting that is silently dropped depending on which file you put it in, which is what happens to CLAUDE_CODE_TMPDIR in project settings.
The settings reference does connect the two ideas, but it does so in a single trailing sentence placed after the code sample at the very end of the allowUnsandboxedCommands entry:
Settings reference, verbatim: "To see when commands you type yourself at the ! shell-mode prompt run sandboxed, see strict sandbox mode."
One cross-reference, correctly placed, easy to scroll past.
"Strict" has three named exits, not one
It is worth counting the documented ways a command can end up outside the sandbox while strict sandbox mode is on, because the name suggests zero and the answer is three.
- A command in
excludedCommands. The sandboxing page states the limit in the same sentence that defines strict mode: every command Claude runs must run sandboxed "unless you've listed it inexcludedCommands". The settings reference describes that key as naming commands that "always run outside the sandbox". This one is intentional, is yours, and is the reason organisation-approved tooling can still work. - A command you type at
!, in an interactive session, on macOS, or on Linux without the scrub variable. New in v2.1.260. - Nothing else. The
dangerouslyDisableSandboxretry, which is the exit the setting exists to close, really is closed. That part works exactly as advertised.
If you are auditing sandbox settings generally, the companion case worth knowing is blockReadsOutsideWorkingDirectories, where setting it to false does nothing, for a different reason again. Exit 1 has always been there and is well understood. Exit 3 is the feature. Exit 2 is the one that appeared this month without appearing in most people's mental model, and it is the only one of the three that a policy author cannot see by reading their own settings file.
How to check what your session is actually doing
Three checks, in increasing order of effort.
Check the version first. Run claude --version. If you are below 2.1.260 none of this applies to you yet, and if you are on the stable channel you are currently below it.
Open the panel. Run /sandbox in a session. The docs describe three tabs: Mode, which chooses how sandboxed commands are approved; Overrides, which the docs identify as "the allowUnsandboxedCommands setting" and which displays the false state as Strict sandbox mode; and Config, which shows "the resolved sandbox settings". The Config tab is the one that matters when several settings files are in play, because it shows what actually resolved rather than what you wrote.
Note what the panel will not tell you: it reports whether strict sandbox mode is on, not whether your shell-mode commands are covered by it. That second question depends on your session type and your platform, neither of which is a sandbox setting.
Test it directly. In a session with strict sandbox mode on, type ! and then a command that reads a path your filesystem.denyRead list blocks. If it returns the contents, shell-mode is outside the sandbox on your machine. This is the only check that answers the question for your exact combination of version, platform and session type, and it takes about ten seconds.
What this means if you wrote an organisation policy
The recommended managed-settings block for enforcing the sandbox is this, and it is unchanged:
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false
}
}
Anthropic's own guidance for administrators now spells out the limit directly underneath it:
Sandboxing reference, verbatim: "This configuration sandboxes the commands Claude runs. A developer can still type a command at the ! shell-mode prompt and run it outside the sandbox, with the same access they already have in any terminal."
That sentence deserves to be read as what it is: a scope statement, not a warning. The final clause is the important one. A developer typing at the ! prompt has "the same access they already have in any terminal", which is to say the policy was never a containment boundary around the human. It was a containment boundary around the agent, and it still is.
Where it bites is if you sold it internally as the former. Three cases where the distinction is load-bearing:
- Compliance framing. If a control document says "all commands executed within Claude Code are sandboxed", that statement was true of interactive sessions before 3 September 2026 and is now true only of the agent's own commands.
- Shared or bastion machines. The gap gives a developer exactly the access they already have. That is fine when the developer is the machine's owner and is worth thinking about when they are not.
- CI and automation. These usually run as background sessions, which the docs place squarely in the still-sandboxed column. Your automation is probably unaffected. Confirm it rather than assume it.
sandbox.allowUnsandboxedCommands carries a Scope of "Any file" in the settings reference, meaning it can be set in any settings file rather than being managed-only. The settings reference recommends false "in managed settings for policies that require strict sandboxing", which is the right place for a control you do not want a project to influence.
What to actually do
If you are on Linux or WSL2 and want the old behaviour back, set CLAUDE_CODE_SUBPROCESS_ENV_SCRUB in the environment. Read its full entry first, because it is not a free switch: it strips credentials from every subprocess, which is usually what you want, and it isolates the PID namespace, which means ps, pgrep and kill inside Bash can no longer see host processes. If a workflow of yours greps ps output, that workflow will change behaviour.
If you are on macOS, there is no documented equivalent for interactive sessions. The honest options are to accept that ! behaves like your terminal, or to move the work into a background session, or to isolate at a layer below Claude Code entirely, such as a VM or container. On Linux the underlying isolation comes from bubblewrap, and on macOS from the built-in Seatbelt framework, so this is a platform capability difference rather than a preference.
If your concern is the agent and not yourself, change nothing. The flag still does exactly what it was introduced to do in v2.0.30, and none of this weakens it.
Whatever you do, check your version. At the time of writing, npm dist-tags for @anthropic-ai/claude-code read latest: 2.1.263 (published 6 September 2026) and stable: 2.1.236 (published 19 August 2026). Because 2.1.236 predates 2.1.260, the two release channels currently disagree about whether your typed commands are sandboxed. Run claude --version before concluding anything about your own machine, and re-check the dist-tags rather than trusting this paragraph, since they move.
What I did not test
Everything above is read from Anthropic's published documentation, the anthropics/claude-code changelog, and npm registry publish timestamps. I did not run an interactive Claude Code session under strict sandbox mode on either platform to observe the ! prompt escaping, and I did not run a v2.1.259 build to observe the prior behaviour. The claim that the prior behaviour was different rests on Anthropic's own sentence stating it, not on a reproduction here.
I also did not verify how allowUnsandboxedCommands merges when several settings files set it at different scopes. The settings reference gives its scope as "Any file" and its default as true, and it does not describe merge semantics for this key the way it does for some others, so treat cross-scope precedence as unestablished rather than assuming either direction.
If you do reproduce it, the fastest check is to enable strict sandbox mode, type ! followed by a command that reads a path your sandbox denies, and see whether it succeeds.
Written by
Sofia NievesSofia works on agent evaluation and reliability. She writes about measuring LLM systems before and after they reach production.
Frequently asked questions
Does allowUnsandboxedCommands: false still sandbox commands I type at the ! prompt?
Not in an interactive session, as of Claude Code v2.1.260 (published 3 September 2026). Anthropic's sandboxing reference states that strict sandbox mode 'applies to the commands Claude runs' and that 'Commands you type yourself at the ! shell-mode prompt run outside the sandbox', with two exceptions: a background session, and a Linux session with CLAUDE_CODE_SUBPROCESS_ENV_SCRUB set. The same page states that 'Before v2.1.260, strict sandbox mode sandboxed shell-mode commands in every session.'
How do I get the old behaviour back?
On Linux or WSL2, set CLAUDE_CODE_SUBPROCESS_ENV_SCRUB in the environment. Anthropic's sandboxing reference lists a Linux session with that variable set as a case where 'every command runs sandboxed, shell-mode commands included'. Read its full entry first: it also strips credentials from all subprocesses and isolates the PID namespace, so ps, pgrep and kill inside Bash stop seeing host processes. On macOS there is no documented equivalent for interactive sessions, so the options are a background session or isolation at a layer below Claude Code.
Does this weaken my organisation's managed sandbox policy?
It narrows what the policy covers, and it does not weaken the control the policy was built on. The dangerouslyDisableSandbox escape hatch that allowUnsandboxedCommands: false closes is still closed, so the agent still cannot retry its own blocked commands outside the sandbox. Anthropic's guidance for administrators now says directly that 'A developer can still type a command at the ! shell-mode prompt and run it outside the sandbox, with the same access they already have in any terminal.' The gap matters mainly if a control document claimed all commands in a session were sandboxed.
Why does searching the docs for 'bash mode' find nothing?
The changelog calls it the ! bash-mode prompt and the documentation calls it the ! shell-mode prompt. Measured across the sandboxing page, the settings reference and the environment variables reference, totalling 469,305 characters of visible text, the term 'bash mode' or 'bash-mode' appears zero times while 'shell-mode' appears seven times. Search for 'shell mode' instead.
Is CI affected?
Probably not. Anthropic's sandboxing reference lists a background session as a case where 'strict sandbox mode covers shell-mode commands too', and automation typically runs as a background session. Confirm it for your own pipeline rather than assuming, since the distinction is session type and not a sandbox setting.
Which versions are affected?
Version 2.1.260 and later. At the time of writing, npm dist-tags for @anthropic-ai/claude-code read latest 2.1.263 (published 6 September 2026) and stable 2.1.236 (published 19 August 2026). Because 2.1.236 predates 2.1.260, the two release channels currently disagree on this behaviour. Run claude --version to see where you are, and re-check the dist-tags rather than trusting a published figure, since they move.
Related tutorials
blockReadsOutsideWorkingDirectories: why setting it to false does nothing (2026)
permissions.blockReadsOutsideWorkingDirectories blocks reads outside your working directories in every permission mode, including bypassPermissions. Writing false does not turn it off, because the key is a logical OR across all settings sources. Plus the 53-hour macOS defect window, dated from the npm registry.
CLAUDE_CODE_TMPDIR is ignored in project settings (2026)
Claude Code v2.1.251 stopped project settings setting CLAUDE_CODE_TMPDIR, CLAUDE_CONFIG_DIR, HOME, TMPDIR and the XDG family from a .claude/settings.json env block. Nothing errors. Here is the full ignore list, the four scopes it splits into, and the debug flag that shows you the drop.
Claude Code Memory: CLAUDE.md vs Auto Memory, and What Actually Loads (2026)
Claude Code has two memory systems and only one of them is capped. A precise 2026 walkthrough of CLAUDE.md load order, the auto memory directory, the 200-line-or-25KB index limit, and a runnable linter that measures your MEMORY.md the way Claude Code measures it.