破坏性命令规则

zn-gate 可用来拒绝会清空机器或未经查看就运行下载内容的 shell 命令的六条规则:每条拦截什么、如何开启或关闭,以及这项检查看不到什么。

查看 .md

zn-gate 可以拒绝一小类会清空机器、或未经查看就运行下载内容的 shell 命令。其中两条规则在智能体钩子中默认开启:rm_root_home(递归删除主目录、文件系统根目录或系统文件夹)和 disk_overwrite(写入磁盘设备)。另外四条规则(pipe_to_shell、rc_download、perm_root、fork_bomb)默认关闭,你可以开启它们。你也可以关闭这两条默认规则。

它是防止模型出错或收到不当建议的护栏,不是沙箱。它读取单条命令的文本,只有命令具有下面某种形态时才会拦截。

命令被拦截后不会运行,智能体会被告知原因,并被要求在运行前先请你确认。如果你确实想运行它,请自己在终端中运行。不熟悉的词请查看术语表。

修改设置

对于智能体钩子(zn hooks install 为你的智能体设置的那些),在 ~/.zn/config.json 中设置 hooks.blockDestructiveCommands:

设置 生效的规则
未设置 rm_root_home 和 disk_overwrite(默认)
true 全部六条规则
false 无:检查关闭
规则名列表,例如 ["rm_root_home", "pipe_to_shell"] 恰好这些规则(不是规则的名称会被忽略)
{"hooks": {"blockDestructiveCommands": false}}

环境变量 ZN_BLOCK_DESTRUCTIVE=1 会开启全部六条规则。环境只能增加保护,不能取消保护:ZN_BLOCK_DESTRUCTIVE=0、任何其他值或不设置都会被忽略,仍由配置文件(或默认值)决定。智能体所在的项目可以设置环境变量,因此关闭规则只能通过配置文件进行,而智能体的文件工具无法写入该文件。

检查生效时,钩子会对你的智能体的 shell 工具(例如 Bash 和 PowerShell)运行它。

在你自己的代码中,可以直接调用该函数。调用它就是选择启用:它始终应用全部六条规则。

  • Node.js:来自 zn-gate/lib/client 的 checkCommand(command)
  • Python:来自 zn_gate 的 check_command(command)

两者返回与 evaluate 同类的结果,规则形如 destructive:rm_root_home。参见 SDK 页面。上面的设置只适用于智能体钩子。

它拦截什么

规则 默认 拦截内容 示例
rm_root_home 开启 递归删除主目录、文件系统根目录、顶层系统文件夹或驱动器根目录。也包括对这些路径使用 -delete 或 -exec rm 且没有 -name 之类条件的 find。 rm -rf ~、rm -rf /、rm -rf /usr、Remove-Item -Recurse -Force $env:USERPROFILE、rd /s /q C:\
pipe_to_shell 关闭 未经查看就把下载内容当作脚本运行。 curl https://example.com/install.sh | sh、sh -c "$(curl ...)"、bash <(curl ...)、iwr ... | iex
disk_overwrite 开启 dd 以块设备为 of=,对块设备使用 mkfs、mkswap、wipefs、shred 或 blkdiscard,重定向写入块设备,以及 PowerShell 的 Format-Volume 和 Clear-Disk。 dd if=/dev/zero of=/dev/sda、mkfs.ext4 /dev/nvme0n1p2
perm_root 关闭 对文件系统根目录或顶层系统文件夹使用 chmod -R、chown -R 或 chgrp -R;对主目录使用带全局可写权限的 chmod -R。 chmod -R 777 /、chmod -R 777 ~
fork_bomb 关闭 经典的 shell fork 炸弹,无论函数叫什么名字。 一个在后台调用自身两次的函数
rc_download 关闭 把下载内容写入 shell 启动文件(.bashrc、.zshrc、.profile、/etc/profile、fish 的 config.fish)。 curl -o ~/.bashrc https://example.com/rc

“顶层系统文件夹”指 /bin、/boot、/dev、/etc、/home、/lib、/lib32、/lib64、/opt、/proc、/root、/sbin、/srv、/sys、/usr、/var,在 macOS 上还包括 /Users、/System、/Library、/Applications、/private、/Volumes。更深的路径,例如 /var/lib/apt/lists 或 /usr/local/lib/node_modules/x,不会被拦截。

命令的拆分方式与 zn-gate 钩子的其他检查相同,因此引号、&&、;、管道、sudo、env、nohup 以及类似的包装命令都能被理解。sh -c、bash -lc、eval、pwsh -Command 和 cmd /c 中的代码也会被检查,最多三层。引号中仅仅提到某条命令的文本(echo "rm -rf ~"、提交信息)不会被拦截。

它做不到什么

这项检查只读取命令文本。以下情况不在覆盖范围内,检查会放行:

  • 命令在运行时才拼出的路径:DIR 为空的 rm -rf "$DIR"、在未知文件夹中运行的 rm -rf *,或来自管道的目标。
  • 先保存、之后再运行的脚本(curl -o x.sh ... && sh x.sh),或把下载内容交给不是 shell 的程序(curl ... | python3)。
  • 其他工具和语言(rsync --delete、git clean、删除文件夹的 Python 单行命令),以及顶层以下的路径(rm -rf /usr/local)。
  • 在容器内或另一台机器上运行的命令。
  • 智能体先写入文件、再运行该文件所做的任何事。

对于这些情况,请使用沙箱、容器或你的智能体自带的权限提示。这项检查只是为最常见的灾难性错误多加一道廉价的最后屏障。

效果如何

测试集包含约 1,000 条普通的开发命令(构建、git、包管理器、容器、删除 node_modules 或 dist、curl -o、编辑 .bashrc,以及许多与被拦截形态很接近的命令),以及约 550 条具有被拦截形态的命令,它们由模板生成,参数、目标和虚构主机各不相同。在这个测试集上没有误报,也没有漏报。测试集和规则出自同一批人之手,所以请把它当作回归测试,而不是所有真实命令上的错误率。

如果它拦截了你想运行的命令

请自己在终端中运行该命令。这项检查只适用于智能体。如果某条规则经常妨碍你,可以用上面的设置关闭这条规则(或整个检查)。