技术 · 熟练

拦住危险动作的那道钩子,自己崩了怎么办?

默认是「放行」—— 你得把它改成「拦住」
你写了一钩子来拦「删库」「外传凭据」「改线上配置」。可是钩子本身也会失败:进程起不来、超时、返回一个谁都没预料到的退出码。这时候大多数工具链的默认行为是 —— 静默放行:检查没跑成,动作照做,日志里也看不出少了什么。这正是 Claude Code 官方在 2026-10-08 补上 onFailure 选项的原因:让钩子「启动失败 / 超时 / 异常退出」时阻断该动作,而不是放它过去。同一天官方还紧急修了一个更早的相关缺陷 —— 写成指令式(instruction-based)的提示钩子会放行它本该拦的东西。这一页做三件事:盘出你真正依赖的那几道闸 · 把它们改成失败即拦(fail-closed)· 再补一条「被拦下来之后怎么办」的出口。因为一道自己会崩、崩了就放行的闸,等于没有。
方法 · 一图看懂
1
盘出「真闸」 — 哪些钩子挡住的是不可逆动作(删文件 / 外传数据 / 改线上);只有这几道值得改,其余别设闸
2
把默认值翻过来 — 给每道真闸设「失败即拦」(onFailure=block 一类的选项),而不是等它自己决定
3
分清「两种失败」 — 钩子说「不允许」与钩子说「我不知道」是两回事;后者必须走人工,⛔ 不能自动放行
4
补一条被拦之后的出口 — 闸拦住之后要有明确的下一步(谁来看 / 看哪份日志 / 怎么放行),否则闸会被绕过
原理 · 为什么有效
为什么默认值这么重要:任何「检查 + 放行」的结构都有一个隐含选择 —— 检查没跑成的时候算通过还是不通过。工具链为了不打断流程,默认几乎都选「算通过」。这在日常脚本里无所谓,但在安全闸上它意味着:攻击面不在你的规则写得对不对,而在你能不能让它别跑。官方这次把 onFailure 做成显式选项,等于承认了这条 —— 默认值是可配置的,但你不能不知道它是什么。同族证据是 10-07 那次紧急修复:把规则写成自然语言指令(「Block commands that…」)时,判定会变得不确定,本不该过的动作过了。⇒ 两条推论:① 安全闸别用自然语言写(用命令或 HTTP 钩子这类确定性形式)② 闸的失败方向必须显式声明,不能继承默认。
适用场景
适合:① 你在用 agent 跑有副作用的动作(改文件、装依赖、调接口、动线上环境),并且已经写了钩子来拦;② 你的钩子依赖外部进程(脚本、HTTP 端点、CI 服务)—— 这些都会失败;③ 你在做合规或团队交付,需要能证明「那道闸当时真的跑过了」。
⛔ 不适合:纯只读的场景(读文件、查资料、跑测试)—— 那里加闸只会拖慢节奏,也养不出好习惯。
自测 · 5 问
我依赖的那几道闸,有没有明确写出「失败时是拦住还是放行」?—— 没写 = 继承默认,大概率是放行
闸的规则是写成命令 / HTTP 调用,还是写成一句自然语言?(自然语言那类判定不稳定)
钩子超时的上限设了多少?超时之后是拦还是放?
有没有区分「策略拒绝」与「检查器自己出错」两种返回?(后者绝不该被当成通过)
闸拦住之后,谁来看、看哪份日志、怎么放行 —— 这条出口写下来了吗?
怎么上手 · 验证步骤
上手三步:第一步只改一道闸 —— 挑你手上最不可逆的那个动作(通常是「删」或「外传」);第二步手动制造一次失败(把钩子脚本临时改成 `exit 1`、或把 HTTP 端点指到一个不存在的地址),确认动作真的被挡住了;第三步把「被拦住之后怎么办」写进团队文档或 README,写清看哪份日志、谁有权放行。做完这三步,这道闸才算真的存在。
自检动作:问自己一句 —— 「如果这道钩子今天开始一直失败,我是会因为『动作做不成了』而发现,还是会因为『动作照做了、没人知道闸没跑』而一直不知道?」答案若是后者,说明这道闸当前是 fail-open,需要改。另一条更硬的验证:把钩子整个删掉跑一遍,看下游反应 —— 删掉没影响,说明它本来也没在拦。
[C级]Anthropic Claude Code 官方 changelog(2026-10-08 · hooks 新增 onFailure=block:钩子启动失败 / 超时 / 异常退出码时阻断动作;10-07 v2.1.294 紧急修复「指令式提示钩子放行了本该拦的东西」) [C级]Claude Code 官方 changelog 镜像(2026-10-05 v2.1.290 起 · claude plugin validate 在每个 gating 位列出钩子是否带 .catch) [C级]Claude Code Daily Briefing 2026-10-09(逐版说明 onFailure 的语义变化与「钩子自己崩了检查就被静默跳过」的既有风险) [C级]AgentConn《Your AI Agent's Bottleneck Isn't the Model》(控制面 · 安全闸与 human-in-the-loop 是模型吸收不掉的那一层) 同类:给AI操作上权限审批链:危险动作先拦下来等你点头 · 插件从加功能到改行为,差在哪一步?
继续往下读
同级:给AI操作上权限审批链:危险动作先拦下来等你点头 下一级:Agent安全审计清单 随机一篇