
Release notes usually get skimmed for the feature headline. v2.1.309 has none. What it has is a long list of fixes where the agent’s guardrails did not do what their documentation said. If you run Claude Code unattended, in CI, or with auto mode, this is the release to read line by line. Everything below comes from the official changelog. I have not run this version, so the behavior claims are the changelog’s, not mine.
Sandbox escapes, closed#
Several bullets describe cases where a sandboxed command could do more than the sandbox policy intended:
- Sandboxed Bash commands on macOS and Linux were running the shell’s startup files outside the sandbox before each command. Startup files are user-writable code that runs on every command, so this is the kind of gap you want closed.
- macOS
denyWriteglob patterns did not apply at a path’s real location when the pattern’s folder was reached through a symlink. - Sandboxed commands and auto-accepted edits could modify the MCP config file passed with
--mcp-config. An agent that can rewrite its own tool list can grant itself new servers. - On Linux, sandbox write denies lifted when a background command outlived the session.
- Profile store write protection did not apply when the config directory was reached through a symlink.
The pattern is symlinks and ordering. Both are classic sandbox bugs, and both are what a prompt-injected agent would probe first. Anthropic fixing them is good. The lesson for you is to treat the sandbox as one layer, not the layer.
Permission checks that trusted too much#
A second cluster is in the Bash permission logic:
- The permission check trusted a variable set by a command whose redirect can fail to open.
- Some compound commands that
cdbefore runninggit, when thecdwas wrapped or prefixed, skipped the prompt that a plaincdtriggers. - An
Edit(path)deny rule did not block a Bash redirect to that path in some commands that also held a subshell. - On Windows, PowerShell checks auto-approved some
Set-Locationorcdcommands that carried extra arguments. They now prompt. - PowerShell hooks did not block when the program exited with code 2, and on Windows
PreToolUseandPermissionRequesthooks with"shell": "powershell"failed open if Git for Windows wasn’t installed.
That last one deserves a pause. A hook that fails open is a control that quietly turns itself off. If you rely on hooks as policy enforcement on Windows machines, upgrade, then test that a deliberately failing hook actually blocks.
Permission rules written as string patterns against shell commands will always have edge cases, because shell syntax is enormous. Deny rules are a speed bump for a confused agent, not a barrier against an adversarial one. For real isolation use the sandbox, a container or a disposable worktree.
Worktree isolation guard#
Worktree-isolated sessions are how many of us run parallel agents, and the guard that keeps each agent inside its tree got attention:
- Some locale-prefixed commands and some zsh arithmetic commands were accepted when the guard should have refused them.
- Worktrees and branch checkouts that Claude Code creates now ignore git replace refs, as its other git operations already did.
- Worktree creation and reuse no longer lets git fetch objects on demand. In a partial clone with a Bash sandbox configured, objects are fetched first.
If you run several agents against one repo, this is your isolation story, and it just got tighter. It is also another reminder that “isolated” is a property of a specific guard implementation, not of the word.
Behavior changes that may surprise you#
The “Changed” bullets are the ones that can break a pipeline:
claude ultrareviewnow requires workspace trust. It asks on a terminal and otherwise refuses. Scripts must pass--trust-workspace, which takes no value, so put a PR number or base branch before it. Or setCLAUDE_CODE_DISABLE_ULTRAREVIEW_TRUST_CHECK=1. If you have a CI job callingclaude ultrareview, expect it to fail until you update it. Prefer the flag over the env var: the flag is visible in the command, the env var is a global off switch.- Dangerous
rmandrmdirin bypass permissions mode on the Desktop app and VS Code are now denied immediately with a rewrite hint, instead of raising a prompt. That helps unattended sessions: the agent gets feedback and tries another route instead of hanging on a prompt nobody sees. sed -inow gets the standard Bash prompt and runs as written, no longer as a simulated file-edit preview. Like other Bash edits, it is not restored by/rewind. If you usedsed -iand relied on rewind as a safety net, commit before you let the agent do bulk rewrites.- Commands excluded from the sandbox now ask before writing to sandbox write-list paths when the sandbox is enabled but cannot run, and the unsandboxed fallback is refused there.
Context and reliability fixes#
Not everything is security:
- A nested CLAUDE.md over the size limit now loads only its start. Previously, sessions could compact repeatedly after reading files under a very large nested one. This is a reminder to keep CLAUDE.md files lean. A spec-driven setup lives or dies on instructions the model can actually hold, and a 200 KB instruction file is not one.
- Split-pane agent teammates now inherit the tool deny and
--toolsrules from the leader’s command line. Before, a teammate could have more tools than the leader you restricted. - A disabled MCP server could be reconnected by a later permission prompt in print and SDK sessions. Fixed.
- Long tool output previews could be cut through an emoji, leaving transcripts that
jqcould not parse. If you post-process session logs, this one is for you. - Improved disk-full handling: a Bash command cut off by a full disk now says so and names the folder to free up.
- Fixed Claude notifying unrelated GitHub users by writing role names and placeholders as mentions in PRs, issues and comments.
What to do with this#
- Upgrade, then diff your assumptions. If your threat model said “the sandbox blocks X”, re-read it against the bullets above.
- Update CI. Search your pipelines for
claude ultrareviewand add--trust-workspacedeliberately. - Test your hooks. Make one fail on purpose on each OS you support and confirm the tool call is blocked.
- Keep the human-grade backstops. Git history, branch protection and disposable worktrees are what remain when a guard has a bug.
The bigger picture#
A long list of hardening fixes can read as bad news. I read it the other way. Every serious agent runtime has gaps between the policy it advertises and the policy it enforces. What matters is that someone finds them and ships the fix in the open changelog, in plain language, within days. That’s the difference between a tool built for autonomous use and one that treats autonomy as an afterthought. It’s also why running agents unattended means reading release notes the way you read a security advisory feed.





