
Key Updates in Claude Code v2.1.289 - Fix for Bash deny rules during sandbox auto-allow and teammate support for agent.spawn
This page has been translated by machine translation. View original
I'm Ishikawa from the Cloud Business Division. Claude Code v2.1.289 (released 2026-10-03) is out. In this article, I'll go over the changes and then test whether Bash deny rules are applied when sandbox auto-allow is enabled.
Here is the previous update article.
Update Summary
v2.1.289 includes 27 changes. The breakdown is 1 new feature, 5 security fixes, 19 bug fixes, and 2 improvements. Of the 19 bug fixes, 15 relate to mods and plugins, and all 5 security fixes concern permission rules or organization-managed settings.
Notable Updates
mods' agent.spawn now supports agent team teammates (new feature)
The following 3 points have been added for mods (plugins that run code inside Claude Code).
- The
agent.spawnevent now also fires when an agent team teammate starts - The agent id is now unified across plugin hook events
$.agent.list()now includes idle and waiting states
According to the Mods reference in the official documentation, agent.spawn is an event that fires just before a subagent or teammate starts, and a hook can specify the model or reject the launch. For a teammate, e.isTeammate is true.
For those who want to write a mod that chooses a model for each agent team teammate or blocks their launch, I think the ability to handle teammate startup via agent.spawn will be useful.
Fixed terminal freezing on short code blocks (bug fix)
Fixed an issue where the terminal froze on short code blocks containing many unclosed <script> tags or deeply nested ${ substitutions. Also fixed is an issue where, when there was a short code block containing many unclosed <script> tags, a published artifact page would freeze or crash the viewer's browser tab.
I expect that those who work with short code blocks containing many unclosed <script> tags or code with deeply nested ${ substitutions will be less likely to run into the terminal stopping while a response is being displayed.
Fixed Bash deny / ask rules not being applied when sandbox auto-allow is on (security)
Fixed an issue where Bash deny / ask rules were not applied in the following 2 cases when sandbox auto-allow was enabled.
- Commands prefixed with an environment variable whose value is expanded (e.g.,
TZ="$HOME" rm -rf build) - Commands preceded by a standalone variable assignment
The official sandbox documentation explains that explicit deny rules are always applied even in auto-allow mode. These 2 fixes address cases that were not behaving as that explanation describes.
If you have enabled sandbox auto-allow and are blocking specific commands with deny rules, I think it's best to update early.
Fixes related to user-installed mods and plugins on managed machines (security)
The following 2 fixes relate to environments under organizational management.
- On managed machines (machines with managed settings deployed), deny / ask rules for nested parts of compound shell commands did not take precedence over approval of a user-installed mod
- A user-installed plugin could rewrite the description of the sign-in tool of an organization-managed MCP server
Administrators of organizations that deploy managed settings while allowing users' mods will want to be aware that these 2 issues have been fixed.
Fixed Read deny rules not being applied to files via symbolic links (security)
Fixed an issue where Read deny rules were not applied when a file reached via a symbolic link was @-mentioned, or when it was modified or selected in the IDE.
I think this fix is relevant to those who protect files such as .env with Read deny rules and make heavy use of symbolic links or IDE integration.
Update Details
New Features
- For mods, the
agent.spawnevent now also fires when an agent team teammate starts, the agent id is unified across plugin hook events, and$.agent.list()now includes idle and waiting states
Improvements
- Improved the speed of opening large files in the plugin code pane (highlight layout is now done only once at the final width)
- Improved the line shown to authors when a mod's bundle or pane fails to render; it now shows the mod name and indicates that nothing was rendered
Security
- Fixed an issue on managed machines where deny / ask rules for nested parts of compound shell commands did not take precedence over approval of a user-installed mod
- Fixed an issue where
Readdeny rules were not applied when a file reached via a symbolic link was @-mentioned, or when it was modified or selected in the IDE - Fixed an issue where a user-installed plugin could rewrite the description of the sign-in tool of an organization-managed MCP server
- Fixed an issue where, with sandbox auto-allow enabled, Bash deny / ask rules were not applied to commands prefixed with an environment variable whose value is expanded (e.g.,
TZ="$HOME" rm -rf build) - Fixed an issue where, with sandbox auto-allow enabled, Bash deny / ask rules were skipped when a command was preceded by a standalone variable assignment
Fixes
- Fixed terminal freezing on short code blocks: Fixed an issue where the terminal froze on short code blocks containing many unclosed
<script>tags or deeply nested${substitutions - Fixed browser tab freezing on published artifact pages: Fixed an issue where, when there was a short code block containing many unclosed
<script>tags, a published artifact page would freeze or crash the viewer's browser tab - [VSCode] Reverted the
claude auth statuschange: Reverted theclaude auth statuschange in v2.1.288 that may have caused frequent sign-outs - Fixed stale plugin display for local-folder marketplaces: Fixed an issue where
plugin list/plugin eval/plugin updateshowed stale copies, and an issue where hot reload did not work with a symlinked--plugin-dir - Fixed freezing at startup due to an unknown border style: Fixed an issue where startup would freeze or force-quit when a plugin rendered a Box with a border style the terminal did not recognize
- Fixed session termination caused by asynchronous plugin exceptions: Fixed an issue where supervised sessions and background sessions terminated when a plugin's screen handler threw an exception asynchronously
- Fixed session termination caused by a mod's
ui.renderhook: Fixed an issue where, if a value written by theui.renderhook caused an exception while rendering a line, the session ended with "unrecoverable interface error". The engine's own line is now rendered instead - A quietly welcome fix: Fixed an issue where installed mods were not loaded in the first session after an upgrade. I think this fix saves the trouble of hunting for the cause when a mod doesn't work right after updating.
- In addition, many other minor bugs have been fixed, including rendering of links in the plugin pane, behavior when a mod's pane, band, or
Clientregion fails to render, the verdict ofclaude plugin validate, and display of text containing control characters.
Trying Bash deny rules with sandbox auto-allow
In v2.1.289, I used claude -p to check whether deny rules are applied to commands with an environment variable prefix. So as not to change my usual settings, I placed temporary settings files in a working directory and passed them with --settings, and used --setting-sources project so that user settings (~/.claude/settings.json) are not loaded.
Step 1: Create a working directory
Create a new directory that contains no .claude/ directory or git repository, and move into it.
% mkdir -p ~/cc-handson-sandbox-deny
% cd ~/cc-handson-sandbox-deny
Step 2: Run with a settings file that has a deny rule
The settings file (settings.json) is as follows.
% cat > settings.json <<'EOF'
{
"permissions": { "deny": ["Bash(touch *)"] },
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"failIfUnavailable": true
}
}
EOF
This denies touch with a deny rule and enables sandbox and auto-allow. failIfUnavailable is a setting that prevents commands from running without the sandbox when the sandbox cannot be started.
With this configuration, to reproduce the form targeted by the fix (an environment variable prefix whose value is expanded), I have it run touch prefixed with TZ="$HOME".
% claude -p --max-turns 1 --output-format json \
--setting-sources project --settings ./settings.json \
'Run exactly this Bash command: TZ="$HOME" touch denied.txt' > result.json
Step 3: Run with a settings file without the deny rule
To confirm that the denial is due to the deny rule, I create settings-control.json, which removes permissions and keeps the sandbox content the same.
% cat > settings-control.json <<'EOF'
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"failIfUnavailable": true
}
}
EOF
I ran a command of the same form.
% claude -p --max-turns 1 --output-format json \
--setting-sources project --settings ./settings-control.json \
'Run exactly this Bash command: TZ="$HOME" touch allowed.txt' > result_control.json
Step 4: Compare the results
These are the results of extracting the necessary fields from the result JSON with jq and checking whether the files exist.
% jq '{subtype, terminal_reason, permission_denials}' result.json
{
"subtype": "error_max_turns",
"terminal_reason": "max_turns",
"permission_denials": [
{
"tool_name": "Bash",
"tool_use_id": "toolu_01GEtWFEFRvt9Yvq7Hyua6wn",
"tool_input": {
"command": "TZ=\"$HOME\" touch denied.txt",
"description": "Create empty file denied.txt"
}
}
]
}
% ls denied.txt
ls: denied.txt: No such file or directory
% jq '{subtype, terminal_reason, permission_denials}' result_control.json
{
"subtype": "error_max_turns",
"terminal_reason": "max_turns",
"permission_denials": []
}
% ls allowed.txt
allowed.txt
With the deny rule, TZ="$HOME" touch denied.txt was recorded in permission_denials, and denied.txt was not created. Without the deny rule, permission_denials was empty and allowed.txt was created. In both cases subtype is error_max_turns because the run ended after reaching the --max-turns 1 limit.
Together with the control experiment, I was able to confirm that commands with an environment variable prefix are also stopped by deny rules. I think it has become easier to combine execution via auto-allow with restrictions via deny rules.
Conclusion
With agent.spawn on teammate startup and state retrieval through $.agent.list(), the range in which mods can handle agent teams has expanded. Together with the permission rule fixes, I think this is a good time to start trying extensions using mods.
If you combine sandbox auto-allow with deny rules, or write mods, why not update and give it a try?
References
