首页/文章/Claude Code 安全 hook 崩溃仍放行?在新加坡 Mac mini 上改成失败即拦截

Claude Code 安全 hook 崩溃仍放行?在新加坡 Mac mini 上改成失败即拦截

· Zumac.Ai

安全 hook 为什么会「拦不住」

你给 Claude Code 配了 PreToolUse hook,本意是:写 .env、执行危险 shell、外联未知地址时先过一遍检查。脚本写好了,平时也管用。直到某一天脚本依赖缺了、jq 解析失败、或者超时被掐断——操作仍然过了。

这不是偶发 bug,而是默认策略:除了明确的拦截信号,多数失败会被当成「非阻断错误」,动作继续执行。安全场景里,这叫 fail-open:守卫倒下,门还开着。

Claude 账号由你自己开通并登录,请遵守 Anthropic 的服务条款与支持地区规则。本文只讲怎么搭一个稳定合规的使用环境,不涉及共享或转卖账号。Zumac.Ai 与 Anthropic 没有官方合作关系。

PreToolUse / PostToolUse 各自管什么

用白话说:

  • PreToolUse:工具调用之前跑。可以拦截——适合「禁止写密钥文件」「禁止某些 Bash」「禁止某类网络请求」。
  • PostToolUse:工具调用已经成功之后跑。不能撤销刚才那一步,最多把警告塞给 Claude——适合审计、格式化提醒,不适合当最后一道闸。

拦截策略应写在 PreToolUse(或能在动作发生前否决的事件)上。PostToolUse 再严,也挡不住已经跑完的命令。

退出码:哪一种才算「拦住了」

Claude Code 看 hook 进程的退出码大致是这样:

  1. 退出 0:成功。若 stdout 里有合法 JSON 决策,按 JSON 执行;没有就放行到正常权限流程。
  2. 退出 2:阻断错误。在 PreToolUse 上会阻止这次工具调用,stderr 会作为原因给到 Claude。
  3. 其他退出码(1、127、脚本崩溃、路径写错导致起不来):默认是非阻断错误——界面上可能出现 hook error 提示,但工具调用照样继续。
  4. 超时:命令/http 类 hook 到点被取消时,多数事件同样不会拦下动作。

所以「脚本报错了」≠「动作被拦了」。只有 exit 2(或合法 JSON 里明确 deny / block),才是真正的拦截。若你希望连脚本崩溃、超时、文件丢失也一律禁止动作,需要在 hook 配置里加上 onFailure: "block"(需较新的 Claude Code 版本支持该字段)。

准备清单

  • 一台常开、不休眠的 Mac mini,已安装 Claude Code,并用你自己的账号登录。
  • 能用 SSH 或 UU 远程连接进入这台机器;终端里有 git、tmux、jq。
  • 一个真实项目,准备把安全 hook 放进仓库的 .claude/ 目录。

步骤一:写一个「失败就 exit 2」的检查脚本

在项目里建 .claude/hooks/deny-secrets.sh:

``bash #!/usr/bin/env bash set -euo pipefail input=$(cat) # 解析失败也要拦截,不要落到「非阻断」 path=$(printf '%s' "$input" | jq -er '.tool_input.file_path // empty' 2>/dev/null) || { echo "hook: invalid JSON input" >&2 exit 2 } case "$path" in *.env|*/.env|*/secrets/*|*/credentials*) echo "Blocked: writing secret-like path: $path" >&2 exit 2 ;; esac exit 0 ``

要点:

  • set -euo pipefail:中间任一步失败就退出,避免「半截成功却 exit 0」。
  • jq 失败时主动 exit 2,而不是让 shell 以 1 结束(1 默认不拦)。
  • 命中规则时写清 stderr,再 exit 2。

chmod +x .claude/hooks/deny-secrets.sh。

步骤二:在 settings.json 里挂上,并打开失败即拦截

在项目 .claude/settings.json(可进 git,团队共享)里:

``json { "hooks": { "PreToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/deny-secrets.sh", "args": [], "timeout": 10, "onFailure": "block" } ] } ] } } ``

  • matcher:只在写/改文件时触发,减少无关噪音。
  • args: []:用 exec 形式启动,路径占位符更稳。
  • onFailure: "block":脚本不存在、崩溃、超时、非法输出时,同样阻止工具调用——这才是安全 hook 要的 fail-closed。
  • 没有 onFailure 时,缺文件、超时往往只是提示一下,危险操作仍会放行。

网络类、密钥扫描类 hook 同理:真正拒绝用 exit 2 或 JSON permissionDecision: "deny";配置层再加 onFailure: "block",防止守卫自己挂掉。

步骤三:用包装脚本兜住「崩溃 ≠ 放行」

有时业务检查逻辑很长,你不想每个分支都记得 exit 2。可以套一层:

``bash #!/usr/bin/env bash set -euo pipefail ROOT="${CLAUDE_PROJECT_DIR:?}" if ! "$ROOT/.claude/hooks/check-inner.sh"; then echo "security hook failed; blocking" >&2 exit 2 fi ``

内层随便怎么写;外层保证:非零就变成 exit 2。再配合 onFailure: "block",启动失败也不会漏网。

步骤四:把 hook 放进 git,在常开 Mac mini 上统一跑

笔记本合盖、换网、系统更新,都容易让「以为开着的守卫」悄悄失效。更稳妥的做法:

  1. 把 .claude/hooks/ 和 .claude/settings.json 提交到项目仓库(密钥仍走环境变量,不要写进仓库)。
  2. 在常开的新加坡 Mac mini 上 git clone / git pull,日常只在这台机器上开 Claude Code 长会话。
  3. 用 SSH 或 UU 远程连接从任意设备进入同一台机器,守卫脚本只有一份,不会「这台改了那台忘了」。

可选:个人全局规则放在 ~/.claude/settings.json,项目规则放在仓库里;两套都要自检「失败是否拦截」。

步骤五:在 tmux 里做一次真实拦截测试

``bash tmux new -s hooks-test cd /path/to/your/project claude ``

然后依次验证:

  1. 让 Claude 写一个普通源码文件——应正常通过。
  2. 让它创建或覆盖 .env——应被拦,transcript 里能看到 hook 的 stderr。
  3. 故意搞坏守卫:临时 chmod -x 脚本,或改错路径,再触发写文件。若已设 onFailure: "block",应同样被拦;若没设,你会看到「非阻断」却仍写入——这就是 fail-open 的现场演示。
  4. 测完立刻恢复可执行权限和正确路径,再确认正常拦截回来。

从子目录启动 Claude Code 时,项目级 .claude/settings.json 有时不会被加载。习惯在仓库根目录启动,或把关键守卫放到用户级 settings,并定期用 /hooks 确认当前会话真的注册了这些 hook。

为什么放在一台常开的新加坡整机上

安全 hook 的价值在于每一次工具调用都过同一道闸。机器休眠、会话断线、多台电脑各装一份半成品脚本,都会把 fail-closed 打回 fail-open。一台 7×24 在线的 Mac mini,tmux 里挂着长会话,hook 目录跟代码一起 git pull,你用 SSH 或 UU 远程连接进去,看到的就是同一套守卫。

Zumac.Ai 提供的就是这样的环境:位于新加坡家庭宽带上的实体 Mac mini M6,整机独享(一人一台物理机),支持 SSH 和 UU 远程连接,FileVault 全盘加密,退租时抹机重装。新客户整机租用 ¥999/月起,季付、半年付、年付有折扣。实际延迟取决于你本地的网络线路,建议先租一个月,把自己的 hook 仓库和拦截测试跑通。

小结

  • PreToolUse 才能拦住工具;PostToolUse 只能事后提醒。
  • 默认失败是 fail-open:崩溃、超时、exit 1 往往不拦动作。
  • 明确拦截用 exit 2(或 JSON deny);安全 hook 再加 onFailure: "block"。
  • 用外层包装脚本把「任何非零」收成 exit 2;脚本进 git,在常开 Mac mini 上用 tmux 实测。

有问题可以在 Telegram 联系 @singatao,或直接看 价格与付款周期。

Zumac.Ai 新加坡 Mac mini M6,整机独享,¥999/月起,联系 Telegram @singatao。
查看方案与费用 · 帮助中心

返回首页 · 更多文章

Telegram 客服