Interpreter deletes of root or home now block
Python, Perl, Node and Ruby deletes of root or home now block
Plus explain --shell, and a DeepSeek Harness notice for unchecked plugin tools
CC Safety Net 2.6.19 closes a gap in how it reads interpreter code. A Python, Perl, Node or Ruby one-liner that recursively deletes the root or home directory now gets blocked, at every safety level. This release also gives explain a shell option, and has DeepSeek Harness tell the agent when a plugin's shell tool went unchecked.
The gap
This one-liner used to get through
Here's the gap. The hook already blocks a shell delete of root or home. But an interpreter's own delete call, like Python's rmtree pointed at slash, was allowed in inline code, heredocs and standard input. In 2.6.19 that command stops, with the rule interpreter dot dangerous command.
Python, Perl, Node and Ruby
Each language’s own tree delete now hits the same rule
Python
shutil.rmtree('/')✖ BLOCKEDPerl
rmtree($ENV{HOME})✖ BLOCKEDNode
fs.rmSync(os.homedir(), { recursive: true })✖ BLOCKEDRuby
FileUtils.rm_rf(Dir.home)✖ BLOCKEDA literal root, or a home lookup · in inline, heredoc and stdin code · at every safety level
Each of these languages has its own way to delete a whole tree, and each one is covered. Python's rmtree, Perl's rmtree, Node's rmSync with recursive set to true, and Ruby's rm_rf. The target can be a literal slash, or a home lookup like Python's expanduser or Perl's HOME variable. It applies to inline code, heredocs and standard input, at every safety level.
What still runs
Everyday cleanup still runs
shutil.rmtree('dist')✔ ALLOWED a relative build folderfs.rmSync(os.homedir())✔ ALLOWED not recursiveshutil.rmtree(os.path.join(
os.path.expanduser('~'), 'build'))✔ ALLOWED a joined path is not resolvedOrdinary cleanup is untouched. Deleting a relative folder like dist still runs, and so does a delete of home that isn't recursive. A computed or joined path also goes through, because the hook doesn't resolve it. So a tree delete of a build folder joined onto home is allowed. The rule only matches a literal root, or a home lookup passed in directly.
explain --shell
explain can now read a command as POSIX or PowerShell
| auto | ✖ BLOCKED | powershell.remove-item-root-or-home |
| powershell | ✖ BLOCKED | powershell.remove-item-root-or-home |
| posix | ✔ ALLOWED |
Explain shows why the hook would allow or block a command. Until now it always parsed in auto mode. The new shell flag reads the command in the dialect of the host tool that ran it, such as Claude Code's Bash or PowerShell tool. Take a Windows rmdir of the D drive root. Read automatically or as PowerShell, it blocks as a root delete. Read as POSIX, it's allowed. Any other value is rejected with an error and the usage line.
DeepSeek Harness notice
The agent hears when a plugin’s shell tool went unchecked
The install output no longer lists other plugins or prints the declare hint.
CC Safety Net did not check the command ops_bash just ran.
npx -y cc-safety-net rule tool add ops_bash
On DeepSeek Harness, a plugin can bring its own shell tool, and CC Safety Net checks it only after you declare it. Now, the first time an undeclared tool runs a command in a session, the agent gets a notice. It says to find out where that tool runs its commands, and to declare it only if they run on this machine. That replaces the hint the installer used to print, which only showed up at install time.
Upgrade
Upgrade to 2.6.19
To upgrade, run the update command, which pulls the latest release. Expect a change in behavior. Interpreter code that recursively deletes root or home now stops. Undici and zod also get version overrides past new audit advisories. And a joined path still isn't resolved. Python, Perl, Node and Ruby deletes of root or home now block.






