The analyzer now reads inside Windows cmd /c and powershell -Command wrappers, closing a gap where a recursive delete nested in either one was allowed. This release also fixes a hook crash on long interpreter string literals, clears a batch of standard-mode secret-protection false positives, and ships a Cursor plugin.
Highlights
- Added analysis of commands nested in Windows shell wrappers. In v2.6.0 forms such as
cmd /c "rmdir /s /q C:\"andpowershell -Command "Remove-Item -Recurse -Force C:\"were allowed; they are now blocked as catastrophic hard stops, in every permission mode. (#226, #227) - Fixed the v2.6.0 hook failing closed with "command analysis failed unexpectedly" on commands containing a very long string literal, such as a
python3 - <<'EOF'script that edits source files. (#224) - Added a Cursor plugin, so CC Safety Net can be installed from Cursor's Customize screen instead of the
npxuser hook. (#230)
Added
- Added the
cmd.recursive-delete-*rule family forrmdir/rd/del/erasewith/sinside acmd /c,cmd /k, or Git Bash//cbody. Targets are judged by the existing recursive-delete rules against the outer working directory, and every other piece of the body is analyzed as a command of the outer shell, so arm -rf /nested in acmdbody is also denied. Deletes that stay inside the current directory remain allowed. (#226) - Added the
powershell.nested-recursive-delete-unreadrule. Apowershell/pwshinvocation in the one shape the analyzer reads — optional-NoProfile,-NonInteractive,-NoLogo, or-ExecutionPolicy, then-Command/-cwith literal script words — is analyzed as PowerShell; any other form that names a delete command and a recursive switch is blocked instead of allowed.-EncodedCommandis refused as an unverifiable shell source. (#227)
Changed
- Reduced standard-mode secret-protection false positives. Words outside string literals in Python and JavaScript code are no longer treated as paths; f-strings and untagged JS templates are masked as literals; and when code holds an access marker, Python and JavaScript literals are judged by position, so a collection element, dict key or value, subscript key, or
in/==/!=operand counts as data rather than a path. (#219, #220) - Relaxed standard mode for names that are created or counted rather than read: a
mkdirortouchoperand,wcwith only count options,grep/rglimited to names, counts, or exit status, aforlist word whose variable reaches no reader,tailscale cert --cert-file/--key-fileoutputs, and the input ofopenssl x509 -in. Each relaxation turns off wherever the name could still reach a reader — a later pipe, a coprocess, a command or process substitution, or an interpreter execution call — and none of them relax home-directory paths, coding-CLI credential paths, or configured deny paths. (#222, #225) - Relaxed a literal that only names the file a write creates (
Path(...).write_text,open(p, 'w'),writeFile/appendFile/Bun.write) like an output redirection, and only where no such file exists. (#225) - Exempted
.env.tplin every mode, alongside.env.example,.env.sample, and.env.template. Home-directory rules now run before the template exemptions, so~/.ssh/.env.tplstays protected. (#222) - Redesigned the local policy GUI (
cc-safety-net gui) for readability: tidier Protections toolbar, disclosures and card headers, visible ends of long paths, fewer repeated labels, and clearer Activity row actions. Activity and Protections filters are now kept in the page address, so Back, reload, and sidebar links behave as expected. (#229) - Simplified the false-positive report: the title is prefilled from the blocked command, and the explanation of what you were doing is now optional in both the GUI form and the GitHub issue template. (#229)
Fixed
- Fixed
rm -rfinside a project being denied asrm.recursive-force-outside-cwdaftercd /d/<project>on Windows with Git Bash. The POSIXcdoperand is now MSYS-normalized before resolving, matching the behavior ofcd D:/<project>. (#223, #228) - Fixed path-variable expansion giving up on an unclosed unsupported
${, which left the rest of the value unexpanded. Later supported variables now expand, and an excessive number of unclosed expansions is refused. (#226) - Fixed
uv run python - <<EOFbodies being walked as shell words instead of analyzed as Python, in every mode. (#225)
Breaking Changes
- A recursive delete handed to
powershellorpwshin any form other than literal-Commandscript words is now denied in every permission mode, including-File, a positional script,-WorkingDirectory, and an outer-expanded word.- Migration: Pass the script as a single
-Commandwith literal paths, after at most-NoProfile,-NonInteractive,-NoLogo, or-ExecutionPolicy.
- Migration: Pass the script as a single
- A
cmd /corcmd /krecursive delete whose quoting can reach cmd as\", or whose target uses a\\?\or\\.\namespace path, is now denied in every permission mode, because cmd does not treat\"as an escape and the target can split down to the drive root.- Migration: Pass each path as its own quoted argument, or use
Remove-Item -LiteralPath.
- Migration: Pass each path as its own quoted argument, or use
- A
cmdbody containing^,%,!, a directory-change word, or a delete the bounded reader cannot parse is refused as an unverifiable shell source, which asks the user where the host can prompt.- Migration: Write the delete with a literal path and no escape or expansion characters, or run it manually.