基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
简历
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
9.0
重磅
AI SCORE
编程提效2026-11-04 15:03

用破坏性命令实测编程智能体护栏

dev.to · AI#智能体安全#命令执行#自动化测试
Editor brief · 编辑速览

作者用 17 条破坏性命令与 16 条正常命令测试执行钩子,旧版本漏放 13 条危险命令,并误拦 5 条正常命令。改用 Shell 语法解析和命令专属规则后,新版本通过了这组测试,但作者承认仍有防护缺口。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

让 AI 编程代理自动执行命令,风险不只在模型会不会犯错,还在拦截它的脚本是否可靠。作者给自己的安全钩子喂了 33 条测试命令,发现 17 条破坏性命令竟然放过了 13 条,包括会清空用户主目录的 rm -rf ~。

这篇最有用的部分,是把「安全感」变成可复现的测试:既测危险命令能否拦住,也测日常工作能否放行。作者换掉旧钩子后拿到了满分,但仍明确留下了两个缺口。满分覆盖什么、没覆盖什么,比换了哪个工具更值得看。

安全钩子要同时交出两份成绩

作者使用 Claude Code 的 bypassPermissions 模式,代理执行命令时不等待人工确认,唯一的刹车是钩子(hook):工具执行动作前,把计划执行的命令交给脚本,由脚本决定放行、拒绝或询问用户。

旧钩子靠正则表达式寻找危险文本,命中后要求人工批准。因此,绕过确认模式下仍可能弹出提示。作者最初的不满是它频繁打断正常工作,测完才发现,它对危险操作的保护也很弱。

测试集分成两组:

  • 17 条应拦截的破坏性命令,包括 rm -rf ~、rm -fr /、find ~ -delete、git reset --hard、git push --force 和 bash -c "rm -rf ~"。
  • 16 条应放行的日常命令,包括删除 /tmp 工作目录的 rm -rf $W、chmod +x、pkill 和 while true 循环。

旧钩子只拦住 4/17 条危险命令,还卡住了 5/16 条正常命令。替换后的 cc-safety-net 则分别达到 17/17 和 16/16。

两套安全钩子在33条命令上的拦截与放行成绩

只统计危险命令拦截率,会把「全部拒绝」误当成优秀的安全策略。

误拦同样要测,否则开发者很容易因频繁受阻而关闭保护。测试也不需要真正执行删除:把命令作为文本传给钩子,检查判定即可。

复现时还要保存工具版本、规则等级、预期结果、工作目录和相关变量。尤其是 $W,脱离变量值和路径上下文,它没有唯一的安全含义。

正则为什么漏掉删除,却拦住正常清理

旧钩子的三个错误,都出在文本与 Shell 实际执行语义之间。

首先,它把不以 / 开头的删除目标当作相对路径,进而认为无害。但 ~ 会被 Shell 展开成用户主目录,rm -rf ~ 因此漏过。这里也暴露了一个额外问题:相对路径是否安全,本来就取决于当前目录和目标。

其次,规则只识别 -rf,没有识别作用相同的 -fr。对 rm 来说,两者等价;对文本匹配来说,它们是不同字符串。

第三个错误反而造成误拦。下面这行代码原本想跳过已经由其他逻辑处理的 rm -rf 规则:

if (pattern.test(strippedCommand) && !/rm\s+.*-rf/.test(pattern.source)) {

要看的是 pattern.source:这里检查的是正则表达式的源码文本。其中的 \s 是反斜杠和字母 s,而外层正则的 \s 匹配空白,所以预期的跳过逻辑没有生效。针对 rm -rf $VARIABLE 的规则一直参与检查,连 /tmp 下的正常清理也要求确认。

作者换用 MIT 许可的开源工具 cc-safety-net。它解析 Shell 语法,识别程序、选项、参数和嵌套命令,能够处理 -rf、-fr,也会重新解析 bash -c "..." 里的命令。

接入位置是 ~/.claude/settings.json 的 PreToolUse,执行命令为 node $HOME/.claude/scripts/cc-safety-net/.../cc-safety-net.js hook --coding-cli。原文缩短了路径,不能直接照抄运行。

配置中的 matcher 为空,使钩子接收所有工具动作,作者称读取 .env 或 ~/.ssh 也会被检查。被拒绝时,代理收到原因,再自行调整做法。作者把版本固定并装进独立目录,但没有给出具体版本号。

规则等级也有取舍:Strict 再次拦住了正常的 rm -rf $W,所以作者选择 Standard。

满分之外,还有变量、Python 和沙箱边界

17/17 只说明这 17 条用例通过,作者当前的钩子仍会放过两种删除方式:W=/home/dev/projects; rm -rf $W,以及通过 python3 -c "import shutil; shutil.rmtree(...)" 删除文件。

前者涉及变量值,工具无法确定 $W 指向哪里;后者由 Python 自己删除文件,Shell 层面没有 rm 可拦。原文的 Python 示例带有省略号,只是在说明绕过方式,并非完整可运行代码。

作者接受这两个缺口,依靠频繁推送 Git 和自动备份兜底。但他也提到,自己的自动备份曾静默停摆。备份任务存在,不等于恢复能力有效。

沙箱能在另一层限制文件访问。作者在 Ubuntu 上试用了依赖 bubblewrap 的 Claude Code 沙箱,首次运行所有命令都失败,报错包含 apply-seccomp: write /proc/self/setgroups ... Permission denied。其机器的 sysctl kernel.apparmor_restrict_unprivileged_userns 返回值为 1,AppArmor 限制了相关隔离空间的创建。

文档提供了需要 sudo 安装的 AppArmor 配置,作者则采用免 sudo 的绕法:设置 sandbox.network.allowAllUnixSockets: true。代价是关闭 Unix socket 过滤。

允许部分目录写入后,Go 构建和测试、签名提交、SSH Git 操作及 Docker 基本可用,从 Python 写入主目录也被拒绝。不过三个问题让作者放弃了这套配置:

  • 受保护文件在沙箱中呈现为特殊文件,导致 git add -A 报错。
  • 每条命令执行时,真实仓库里会出现约 25 个空占位文件,正常结束后消失。
  • 在 bypass 模式下,沙箱失败的命令可能无需确认就在沙箱外重试;allowUnsandboxedCommands: false 能关闭这个出口,却解决不了前两个问题。

占位文件尤其影响并发工作:另一个代理或 IDE 恰好执行 git add -A,就可能把它们加入提交;会话被杀死时也可能留下文件。这是作者机器上的实测,不能直接推广为所有 Ubuntu 环境的结论。

我的判断

我认同作者把钩子当普通代码测试,也认同同时衡量漏拦和误拦。语法解析比堆叠字符串规则更适合处理参数顺序和嵌套命令,文中的故障解释也足够具体。

但这里没有大规模对照数据。cc-safety-net 的满分来自作者自选的 33 条命令,原文没有提供足以独立复现的完整用例和版本信息;作者还测试了 dcg,却没有展开弃用理由。因此,这是一份有价值的个人实验记录,不能据此宣布某个工具普遍更安全。

钩子判断命令是否允许,沙箱限制进程实际能做什么,两者覆盖的风险不同。

Python 删除的例子就说明,Shell 规则不能承担完整的文件隔离责任。反过来,沙箱若存在无需确认的外部重试通道,其保护边界也会变化。

作者另一个关机拦截钩子很适合小团队借鉴:它通过 --test 运行 31 条用例,只在命令位置识别 shutdown、reboot、poweroff 和 halt,避免误伤提交说明和搜索文本。下面这段把危险操作和正常文本放进同一组回归测试:

if [[ $1 == --test ]]; then
  fail=0
  while IFS='|' read -r want cmd; do
    if is_power_command "$cmd"; then got=deny; else got=allow; fi
    [[ $got == "$want" ]] || { echo "FAIL want=$want got=$got: $cmd"; fail=1; }
  done <<'CASES'
deny|sudo shutdown -h now
deny|cd /tmp && reboot
deny|bash -c "reboot"
allow|git commit -m "fix graceful shutdown"
allow|grep -rn shutdown .
allow|go test ./... -run TestShutdown
CASES
  [[ $fail == 0 ]] && echo "all cases pass"
  exit $fail
fi

关键是 is_power_command "$cmd":测试只检查文本;但这只是测试入口,原文没有展示判定函数,不能把它当作完整防护脚本。

能拿来做什么

  • 给日常 AI 编程命令建立两组用例,把仓库清理、权限修改、进程终止等正常操作也纳入测试,并记录工作目录、变量和预期结果。
  • 给删除规则补上 -fr、~、变量、bash -c 和 find -delete 等变体,只向钩子传递文本,分别记录危险拦截数与正常放行数。
  • 固定钩子版本和规则等级,每次更新前重跑用例;遇到误拦时,把真实命令加入回归集,再决定调整规则。
  • 使用自动执行模式前,列出 Python 等解释器操作文件的已知缺口,检查沙箱外重试设置,并确认代理无法触及的备份确实能够恢复。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
用规格与四角色分工约束 AI 开发
下一篇
让 Codex 长任务少卡住的配置检查

资讯速览

dev.to · AI · 2026-11-04 15:03

AI 评分 9.0 / 10

相关标签

#智能体安全#命令执行#自动化测试

继续阅读

  • 三款编程助手的 MCP 配置差异速查
  • 用规格与四角色分工约束 AI 开发
  • 让 Codex 长任务少卡住的配置检查
  • 开源兼容层让旧款 Windows 手机跑安卓
  • 用密码学证明API实际运行的模型