This release adds Factory Droid and Devin CLI protection, and makes shell analysis see destructive commands that were previously hidden inside ${...} parameter expansions.
Highlights
- Added protection for Factory Droid and Devin CLI, including hook installation,
doctorreporting, and built-in rules for their credential and config files. (#197, #198, #200) - Commands hidden inside a
${...}parameter expansion are now analyzed instead of skipped, soecho ${x:-$(rm -rf ~/)}is blocked. (#214) - Fixed false blocks on URL query text, so requests such as
curl 'https://example.com/todos?order=id.asc'are no longer treated as reads of a sensitive.ascfile. (#217)
Added
- Added Factory Droid support with
cc-safety-net install --droid, the-fd/--droidhook flags, and a managedPreToolUseentry in~/.factory/hooks.json. (#198) - Added Devin CLI support with
cc-safety-net install --devin, the-dv/--devinhook flags, and a managedPreToolUseentry in the user config ($XDG_CONFIG_HOME/devin/config.json, or%APPDATA%\devin\config.jsonon Windows). Comments in Devin'sconfig.jsonare accepted. The adapter also analyzes the text sent bywrite_to_process. (#200) - Added built-in secret rules for Factory Droid credentials (
~/.factory/auth.encrypted,auth.v2.file,auth.v2.key,auth.v2.loginkeychain) and config (~/.factory/settings.json,hooks.json,mcp.json, and a project.factory/mcp.json), and for Devin CLI credentials (~/.local/share/devin/credentials.toml,~/.local/share/devin/mcp/oauth) and config (~/.config/devin/config.json). Relocations throughXDG_DATA_HOMEandXDG_CONFIG_HOMEare honored. (#197) - Added sensitive-path checks for the
folderandpatternsinputs of glob tools, so a glob over a credential directory is blocked. (#198)
Changed
- Shell analysis now refuses, at every safety level, constructs whose real meaning cannot be determined:
${ list; }function substitutions (including inside heredoc bodies, across line continuations, and when the parser's depth limit cuts them off), a backslash escape inside backticks, an unclosed${, and a quote, backslash, or line continuation inside${ }next to a substitution. Such a command is reported as unanalyzable and denied rather than allowed. (#211, #214) shell: "posix"in the OpenCode plugin now accepts any shell that runs POSIXshsyntax, such asashormksh, by running a short probe through<shell> -conce per executable instead of matching a list of shell names.cmd.exe, fish, nushell, and tcsh are still rejected, and the probe ends at a 10-second deadline. (#209)- Atomic config writes now keep the replaced file's permission bits instead of resetting them to the default. (#198)
Fixed
- Fixed destructive commands being skipped inside a
${...}parameter-expansion operand, a substitution glued to a variable in double quotes (echo "$x$(rm -rf ~/)"), and a double-quoted arithmetic substitution. (#214, #215) - Fixed strict-mode denials of commands that are in fact analyzable: each nested command substitution now tracks its own quote state, so
echo $(dirname "$(command -v node)")andecho $(printf "x'$(git status)'y")are allowed instead of refused as unparseable. (#215) - Fixed built-in extension rules such as
.pemand.ascmatching URL query text. A word holding a query parameter (?key=or&key=) that names no existing file, and the value after a query's=, are no longer read as paths; a file that really has such a name stays protected. A curl-d,--data,--data-ascii,--data-binary,--data-urlencode,-F, or--formvalue is now checked only as the@fileor<fileupload it names. (#217) - Fixed the user policy being read as a project policy when a command runs from the home directory.
policy checkandpolicy applynow refuse and point to--global,rulewrite subcommands refuse,rule migrateskips the project scope, the policy GUI refuses to use the user policy as a project draft, and policy loading no longer counts the user policy twice. Symlinked home directories are matched as well. (#201, #202, #203, #205) - Fixed
uninstall --droiddeleting~/.factory/hooks.jsonwhile~/.factory/settings.jsonexists, which would have let the hooks insettings.jsonload again, anddoctornow reports a managed Droid hook narrowed bycommandRegex. (#198)