This release blocks forced git rm working-tree removal, closes several audit-found analyzer bypasses, and removes common false denials such as ls -la ~/.ssh and eval "$(ssh-agent -s)" at the standard level. Note two breaking --json output changes in doctor and explain.
Highlights
- Added a
git.rm-forcerule that blocks forcedgit rmworking-tree removal (e.g.git rm -rf .) at every safety level, motivated by a real-world incident that destroyed a project (anthropics/claude-code#70687). - Closed analyzer fail-opens found in a security audit:
rm -rf *at a home working directory is now blocked at all levels, and strict mode now catches variable-provenance command heads and substitution-derivedrmflags. - Reduced standard-level false denials: metadata-only
ls/statdiscovery and verifiable local generator sources likeeval "$(ssh-agent -s)"andsource <(kubectl completion bash)are now allowed.
Added
- Added the default-enabled
git.rm-forcerule:git rmwith an effective--force/-fis blocked unless--cachedor--dry-run/-nis present; non-forcedgit rmandgit rm -r --cached .stay allowed. The standard preset now enables 45 rules.
Changed
- Allowed
eval "$(CMD)"andsource <(CMD)at the standard level whenCMDis a single fully literal local command; remote fetchers (curl,wget, ...), shells, command wrappers, and env-assignment-prefixed bodies stay denied, and strict/paranoid still deny every dynamic shell source. Note that the generator's emitted shell itself runs unverified (seeSECURITY.md). - Allowed metadata-only discovery with
lsandstatheads (e.g.ls -la ~/.ssh,stat .env) at the standard level; content access such ascat ~/.ssh/id_rsastays blocked, and strict/paranoid still block both. - Changed the Kimi Code plugin manifest to intercept all tools instead of only
Bash, so the native plugin install protectsRead/Write/Editlike the global-hook install already did.
Fixed
- Fixed
rm -rf *with the working directory at home being allowed at standard: a bare*now classifies as a root-or-home target and is blocked at all levels, while a quoted literalrm -rf '*'(a single file named*) is classified by its actual target. - Fixed strict-mode fail-opens where
c=rm; "$c" -rf dir,$CMD --version, andrm $(printf -- '-rf') dirwere allowed at every level; strict and paranoid now block them while standard verdicts are unchanged. - Fixed statement-level env assignments with space-containing values (e.g.
TMPDIR="/tmp/safe /Users"; rm -rf $TMPDIR/x) escaping shell-state tracking; strict and paranoid now block the word-splittingrmtarget. - Fixed Kimi Code ignoring the per-call
Bashtool_input.cwd: it is now contained against the session directory and used as the execution directory, failing closed on invalid or escaping values. - Fixed Pi tool calls being analyzed under the raw context
cwdinstead of the validated, canonicalized one, and routed Pi's built-infindtool as a read-only glob so searches under protected directories are no longer falsely denied. - Fixed OpenClaw Code Mode JavaScript
execevents being parsed as shell commands and falsely denied, and expanded a leading tilde inOPENCLAW_STATE_DIRandOPENCLAW_CONFIG_PATH. - Fixed OpenCode integration gaps: slash-rooted Windows workdirs pass through instead of failing closed, config and cache roots follow
XDG_CONFIG_HOME/XDG_CACHE_HOME, install now verifies the plugin actually loads, and a non-string configured shell falls back to a sane platform default. - Fixed
doctormisreporting a never-installed Codex plugin as disabled, missing Copilot CLI hooks defined in~/.copilot/settings.jsonand the repo's.claude/settings.json/settings.local.json, and probingcodex plugin listwith a shorter timeout thaninstall, which could report Codex as not installed whereinstallsaw it. - Fixed the Copilot CLI
powershellruntime tool being analyzed with the wrong shell dialect, and the Hermes Agent plugin now resolves the working directory in the host's own order. - Fixed a successful GUI install rendering an empty status box instead of the success report.
- Fixed
explaincrashing with a stack trace and empty stdout on analysis-limit inputs (e.g. a recursion bomb); it now prints a bounded JSON error under--jsonor a plain message on stderr and exits 1. Pipedexplainoutput is also no longer truncated at 64 KiB under the packaged Node binary. - Fixed
explaintrace steps naming functions that do not exist and theenv -Sdenial reason claiming an unreachable condition; the reason now names the real 16,384-token expansion-limit trigger.
Breaking Changes
- Changed
doctor --jsonto report integration versions under a singleversionsmap keyed by integration id instead of twelve flat fields such asclaudeCodeVersion.- Migration: Read
versions.<integration-id>instead of the per-integration*Versionkeys.
- Migration: Read
- Changed
explain --jsontrace output:rule-checksteps emit onerulestring in place ofruleModule/ruleFunction, andenv-strip.envVarsis an array of variable names instead of an object.- Migration: Read
rulefor the rule identity and treatenvVarsas a string array.
- Migration: Read
Removed
- Removed the Pi
Shelltool adapter; the tool no longer exists on the Pi host, and the built-inbashroute is unchanged.