拓冰建站拓冰建站
首页 / 资讯中心 / 正文

davidondrej-skills 代码实现原理:deny-dangerous.sh 用正则拦截危险命令的完整拆解

davidondrej-skills 代码实现原理deny-dangerous.sh 用正则拦截危险命令的完整拆解【免费下载链接】skillsaccess to david ondrejs personal agent skills项目地址: https://gitcode.com/gh_mirrors/skills46/skills️ 本文带你完整拆解 davidondrej-skills 项目中的命令守卫脚本 deny-dangerous.sh它如何在 AI Agent 执行 shell 命令之前用一行行正则表达式拦截rm -rf /这类危险操作。这是 davidondrej-skills 仓库里少有的硬代码防护层——其他内容都是教 Agent 做事的 SKILL.md 提示词而它是一层真正会拒绝执行的守卫command guard。为什么 AI Agent 需要一个命令守卫大模型驱动的编码 AgentClaude Code、Codex、Cursor 等会自己敲 shell 命令。绝大多数时候它删的是node_modules但偶发一次rm -rf ~或git push --force就可能造成不可逆的损失。davidondrej-skills 的解法很朴素在命令执行前设一道正则黑名单。它防的是事故而不是恶意——文档里明确说了混淆过的命令比如把rm -rf藏进 Python 代码是绕得过去的它拦截的是 Agent 会原样打出来的那些经典危险命令。这套方案由三个文件组成全部位于 hooks/ 目录文件角色一句话说明hooks/dangerous-patterns.txt黑名单每行一条正则命中即拦截hooks/deny-dangerous.sh守卫读命令 → 逐条匹配 → 决定放行或拦截hooks/test-guard.sh测试约 200 条用例验证该拦的拦、该放的放整体架构Agent 钩子如何接上守卫各 Agent 都支持执行前钩子PreToolUse / beforeShellExecution每当 Agent 要跑一条 Bash 命令Agent 先把命令包成一段 JSON通过标准输入喂给deny-dangerous.sh脚本以退出码或 JSON 回答放行还是拦截。对应关系见 skills/ops-and-setup/global-agent-guardrails/SKILL.md 中的接线表Claude Code / Codex / Grok命令藏在 JSON 的.tool_input.commandGrok 用.toolInput.command拦截方式是退出码 2 stderr 打印理由Cursor命令在.command字段拦截方式是stdout 输出{permission:deny}JSON脚本用一个命令行参数区分模式见 hooks/deny-dangerous.sh#L19不传参就是默认的退出码模式传cursor就走 JSON 模式。deny-dangerous.sh 逐段拆解从 JSON 到拦截的 5 个步骤整个脚本只有 50 多行逻辑链非常清晰我们按执行顺序拆开看。第 1 步从钩子 JSON 里把命令捞出来CMD$(printf %s $INPUT | jq -r .tool_input.command // .toolInput.command // .command // empty 2/dev/null)见 hooks/deny-dangerous.sh#L31。注意这条 jq 表达式里的//链依次尝试三个字段哪个存在取哪个——这就是一份脚本伺候四个 Agent的兼容点。取不到命令empty就直接放行因为没命令可查。第 2 步三处fail open设计——宁可漏拦不可卡死 Agent这是新手最容易忽略、也是设计最讲究的地方。脚本在三个位置都会主动放行没装jq→ 放行hooks/deny-dangerous.sh#L27解析不了 JSON 就跳过检查避免把 Agent 的每次命令都拦死取不到命令字符串→ 放行hooks/deny-dangerous.sh#L33黑名单文件不存在→ 放行hooks/deny-dangerous.sh#L34这叫故障时开放fail open守卫自身的任何故障都不应阻断正常工作流。代价是守卫坏掉时没有防护——所以配套了下面讲的全量测试。第 3 步逐行读取黑名单并做正则匹配核心就一个循环见 hooks/deny-dangerous.sh#L36-L50while IFS read -r pattern; do case $pattern in |\#*) continue ;; esac if printf %s\n $CMD | grep -qE -- $pattern 2/dev/null; then三个细节值得学case跳过空行和#注释行——黑名单文件可以像配置文件一样写注释grep -qE用 POSIX 扩展正则ERE静默匹配命中一次即停--终结符——防止以-开头的正则被误认成 grep 的选项这是 shell 脚本的老坑第 4 步两种模式的拦截响应命中后按模式分流默认模式stderr 打印拦截理由含命中的那条正则退出码 2终止 Agent 执行hooks/deny-dangerous.sh#L47-L48cursor 模式用jq -cn现场拼一个{permission:deny, ...}JSON 输出hooks/deny-dangerous.sh#L40-L44注意拦截消息里有一句专门写给 Agent 看的话Do not retry it or try to work around the guard不要重试、不要试图绕过直接向用户解释拦截原因——它是在用提示词方式封死 Agent 换个写法再试 的行为。黑名单怎么写dangerous-patterns.txt 的 10 组正则拆解dangerous-patterns.txt 是这套守卫的大脑按 10 个主题分组。挑几个代表性模式看写法。组 1rm 指向根目录 / 家目录(^|[;|[:space:]])rm[[:space:]]((-[a-zA-Z]|--[a-z-])[[:space:]])*[]?(~|\$HOME|\$\{HOME\})/?[]?[[:space:]]*($|[;|])hooks/dangerous-patterns.txt#L10拦截rm -rf ~逐块翻译成人话(^|[;|[:space:]])— 必须出现在行首或;|之后保证rm是独立命令而不是某个词的中间部分((-[a-zA-Z]|--[a-z-])[[:space:]])*— 允许 0 到多个选项参数所以rm -rf、rm -r -f、rm --recursive --force都能匹配[]?— 目标可以带引号rm -rf $HOME也拦(~|\$HOME|\$\{HOME\})— 覆盖家目录的三种写法($|[;|])— 家目录后面必须是命令结尾或分隔符这样rm -rf ~/old-project这种删子目录的合法操作不会被误伤组 4、5fork 炸弹与管道直灌 shellfork 炸弹:(){ :|: };:用一条超长正则精确匹配其结构hooks/dangerous-patterns.txt#L25curl xxx | sh这类从网上拉脚本直接执行的命令匹配curl|wget后跟|再接 shell 的形态hooks/dangerous-patterns.txt#L28组 9、10GitHub CLI 破坏性操作与密码管理器gh repo delete、gh api -X DELETE、gh auth token取令牌整组拦截hooks/dangerous-patterns.txt#L47-L52密码管理器1Password、Bitwarden、pass 等整个禁止 Agent 触碰。这里有个防误报的精妙处理op和pass都是常见英文单词所以裸词不拦只有op后跟真实子命令read、inject 等、pass后跟任意参数时才拦hooks/dangerous-patterns.txt#L57-L59误伤控制什么不该拦global-agent-guardrails 的 SKILL.md 明确了拦截边界只拦灾难级命令不可逆数据丢失、擦盘、删仓库、令牌泄露可恢复的本地命令一律放行。git push --force-with-lease这种安全强推变体也特意留白。test-guard.sh约 200 条用例的回归测试改一行正则就可能引入误报所以 hooks/test-guard.sh 把守卫当被测对象做了全覆盖测试约 90 条必须拦截rm -rf /、sudo rm file.txt、dd of/dev/disk2、fork 炸弹、curl | sh、git push -f、gh repo delete……还包括各种变体伪装如cd /tmp rm -rf ~、多行命令、true | pass inserthooks/test-guard.sh#L41-L133约 60 条必须放行rm -rf node_modules、git push --force-with-lease、chmod 777 ./script.sh改单个脚本没问题只有chmod 777 /才拦、甚至echo please pass the token防止把含 pass 的普通文本误判hooks/test-guard.sh#L136-L193每条用例会同时用两种 JSON 载荷Claude/Codex 形态 Cursor 形态各跑一遍双端都要符合预期hooks/test-guard.sh#L11-L38。最后输出passed: N, failed: 0任何一条失败脚本就以非零码退出。配套 skill 的要求是任何一次修改黑名单后都必须跑一遍全量测试。如何部署到各个 Agent各 Agent 的接线方式在 skills/ops-and-setup/global-agent-guardrails/SKILL.md 里有完整对照表要点归纳为把hooks/下三个文件放到~/.agents/hooks/在对应 Agent 的配置文件里注册钩子Claude/Codex 用PreToolUsematcher 为 BashCursor 用beforeShellExecution并给脚本传cursor参数配置里必须写绝对路径各 Agent 对~的展开行为不一致改完模式跑test-guard.sh以failed: 0收尾文档还记录了几个实战坑Codex 对钩子做哈希绑定改过配置后要重新建立信任否则守卫会被静默跳过Cursor 的failClosed必须保持false否则后台任务的每条命令都会被拦。总结这份 50 行脚本值得抄的设计一份黑名单多个 Agent 共用——jq 字段回退链 命令行参数切模式把多端兼容成本压到最低fail open 兜底——守卫自己坏了绝不拖累 Agent 干活正则锚定命令边界——(^|[;|[:space:]])前缀 结尾分隔符是拦住危险、放过日常的关键测试即契约——拦截与放行双向用例让改一行正则这件高风险操作变得可控如果你想给自己的 Agent 加上同款防护从 hooks/dangerous-patterns.txt 抄一份起步黑名单、配上 hooks/test-guard.sh 的测试框架就是一套完整的最小可用命令守卫。【免费下载链接】skillsaccess to david ondrejs personal agent skills项目地址: https://gitcode.com/gh_mirrors/skills46/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门