Windows下Claude Code钩子可能漏拦命令
仅匹配Bash的Claude Code钩子不会触发PowerShell工具,可能让Windows上的破坏性命令绕过拦截。文章还指出,钩子执行失败的处理方式和仅支持POSIX命令的解析器都是独立检查项。
AI 深度解读
给 Claude Code 配了危险命令拦截脚本,Windows 上就一定能拦住吗?作者补充了此前方案的两个缺口:只匹配 Bash,可能收不到 PowerShell 的调用;hook 启动失败,也需要明确规定是否阻止操作。
更容易被忽略的是,修好配置仍不等于支持 PowerShell。原来的 guard.py 只理解 POSIX 命令。这篇值得读的地方,是把「收到命令」「检查器能运行」「检查结果可信」拆成了三个需要分别验证的问题。
为什么写了 Bash 规则,命令却没有经过检查
Claude Code 的 Bash 和 PowerShell 是两个独立工具。hook 的 matcher 匹配的是工具名,匹配 Bash 不会顺带匹配 PowerShell。
原文引用的文档说明:Windows 没装 Git Bash 时,PowerShell 会自动启用,Bash 则不会注册。此时只匹配 Bash 的 hook 根本不会触发。即使系统装有 Git Bash,只要 Windows 上启用了 PowerShell 工具,Claude 也会把它作为主要 shell;Bash 仍可能用于 POSIX 脚本。
因此,配置需要把 matcher 改成 Bash|PowerShell。按照原文引用的工具文档,两者都通过 tool_input.command 提供命令字符串,检查器可以从同一字段取得输入。
但这个改动只负责把事件送到检查器。
收到 PowerShell 命令,不代表检查器理解 PowerShell 命令。
这和前端给表单接上校验函数很像:函数被调用,只能证明调用链通了,不能证明校验规则覆盖了输入格式。
检查器启动失败,应该让谁决定是否放行
另一个缺口发生在 hook 已经匹配成功之后:Python 可执行文件不存在、脚本路径写错,或者进程崩溃,都会让检查器无法完成工作。
原文引用的失败处理文档指出,hook 失败或超时时,操作通常会继续进入正常权限流程。这里不能理解成「直接执行所有命令」,但也不能继续依赖这个检查器提供保护。
对于 command hook,可以设置 onFailure 为 block,让失败触发对应事件的阻止行为。放在 PreToolUse 上,就是阻止这次工具调用。该能力要求 Claude Code v2.1.295 或更高版本。
Windows 还有一个例外:没有 Git Bash 时,shell form 的 PreToolUse 或 PermissionRequest hook,在未设置 onFailure 的情况下,也可能因失败而阻止操作。因此,不能笼统地说「解释器缺失一定会放行」。更稳妥的做法是显式声明策略。
下面这份 .claude/settings.json 配置,同时处理工具匹配和启动失败,脚本位于 .claude/hooks/guard.py:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|PowerShell",
"hooks": [
{
"type": "command",
"command": "python.exe",
"args": [
"${CLAUDE_PROJECT_DIR}/.claude/hooks/guard.py"
],
"onFailure": "block"
}
]
}
]
}
}
要关注 args 这一行:它选择直接启动可执行文件的 exec form,每个参数分别传入,因此项目路径包含空格时,脚本路径仍是一个完整参数。在 Windows 上,这种形式要求使用真实的可执行文件。
python.exe 只是示例,需要换成机器上实际安装、能够找到的解释器。作者明确说,这份配置经过文档核对,没有在读者的 Windows 环境中实测。
为什么正常退出的 guard.py 仍可能漏掉命令
原来的 guard.py 只理解 POSIX 风格的命令语法。PowerShell 有自己的语法、别名、参数绑定和命令组合方式,把工具名加进 matcher,并不会给脚本补上这些知识。
这会产生比启动失败更隐蔽的问题:检查器正常运行,也正常退出,但它没有正确分析输入。
onFailure: block 处理的是 hook 执行失败。如果脚本误解了命令,或者没有返回阻止决定,这个设置无法补救。PowerShell 覆盖需要对应实现,也需要单独验证;原文给出的配置没有完成这部分工作。
还要分清两个角色:一个 shell 负责启动 hook,另一个工具提交待检查的命令。即使用 PowerShell 启动 Python 检查器,也不会改变事件里命令字符串的语言。
所以,这套修改后的方案仍应被描述为:修正了事件路由和失败处理的 POSIX 检查器。称它为「Windows 命令防护方案」,范围就说大了。
我的判断
我认同作者把三个边界分开检查。安全规则最容易造成的错觉,是配置文件里写了某个工具名,就以为已经覆盖了这个工具的全部行为。这里真正缺少的,可能是事件,也可能是进程,还可能是语法理解。
但这篇给出的是文档核对后的修正方案,没有 Windows 实测结果,也没有拦截准确率、漏报率或不同实现的对照数据。它能帮助定位配置问题,不能据此认定防护已经可靠。
和只依赖正常权限流程相比,额外的 guard 可以表达团队自己的命令规则;代价是团队需要维护解释器、脚本路径和语言支持。显式设置 onFailure: block 也会在检查器不可用时中断正常操作,这是选择失败即阻止策略时需要接受的成本。
如果团队暂时只有 POSIX 检查能力,先如实标明支持范围更有用。把 PowerShell 接进来,可以验证事件链路;把它算进安全覆盖,则还缺实现与验证。
能拿来做什么
- 在 Windows 开发机上,用每个可用 shell 工具分别执行无害命令,并查看 hook 实际收到的工具名和
tool_input.command,确认调用确实经过检查器。 - 核对 Claude Code 是否达到 v2.1.295,再临时把脚本路径改为不存在的文件,请求一次无害的目录列举,验证
onFailure: block是否阻止调用,随后恢复路径。 - 给团队的 AI 编程配置注明 guard.py 支持的命令语言。前端或 Node 项目同时使用 Bash 与 PowerShell 时,应分别验证检查决定,不能共用一个「脚本退出成功」的验收标准。
- 将工具匹配、hook 执行失败和命令分析分成三组验证项。排查漏拦截时,先确认问题发生在哪一层,再修改对应配置或实现。