← 返回全部文章
Analysis · 2026年10月4日 · 9 分钟阅读

Claude Code mod 能越过你的 deny 规则:个人方案实测

我们只测了个人 Max 方案、没有托管设置的机器。在这个环境里,负责让 deny 规则优先于用户 mod 生效的内置防护 mod 没有加载。一个只有 6 行、在权限检查时返回 allow 的 mod,就让被 deny 规则拦下的命令照样执行了。Anthropic 文档写明了这种行为。实际含义是:安装 mod,就把 settings.json 管不到的访问权限交给了它的作者。

30 秒看懂结论

10 月 1 日,Claude Code 2.1.287 加入了 mod(在 Claude Code 进程里运行的插件代码),默认开启。这些 JavaScript 代码可以注册处理函数,查看和修改提示词、工具调用,也可以在系统向你询问之前回应权限检查。

我们写了 7 个小测试 mod,在 Claude Code 2.1.289 上跑了 48 次无界面会话(claude -p),过程中没有交互式提示。账号是个人 Max 方案,机器没有托管设置(managed settings)。每种配置都跑了 3 次,结果均为 3/3:

  • deny 规则拦下的命令,装上一个 mod 就照样执行了。原本被规则拦住的命令,只要加上一个 6 行的 mod,在权限检查时返回 allow,就能执行。
  • deny 规则管不到 mod 自己的调用。Claude 读不了被 Read 规则禁止读取的文件,mod 却通过自己的 API 读到了。
  • 沙箱管不住 mod。Claude 向项目外的目录写文件时被沙箱拦住,mod 启动的进程却能写入。
  • mod 能改写会话记录。我们让处理函数改写即将保存的会话行。对照测试中,会话记录(transcript)里是 Claude 回复的口令。加上 mod 后,同一位置变成了 REDACTED。
  • claude plugin validate 对越过 deny 的 mod 只列出 tool.check。它的 calls: 一行写着 “nothing on $“,只观察权限检查、不改变决定的 mod 也一模一样。

权限、沙箱和会话记录的这些行为,Anthropic 文档都有说明。另有一项网络结果与文档不符,后文会单独说明。这些测试放在一起看,含义很明确:安装 mod 后,它的代码能访问一些 Claude Code 权限规则和 Bash 沙箱管不到的资源。

mod 是什么

mod 是带有钩子模块的插件。这个模块是一个 JavaScript 或 TypeScript 文件,由 Claude Code 加载到自己的进程中。当工具被调用、用户提交提示词、会话行即将保存等事件发生时,对应的处理函数就会运行。它可以保持原样,也可以改写内容,还可以直接提供结果,让原本的处理流程不再执行。

Claude Code 会向每个处理函数传入一个名为 $ 的 API 对象。钩子模块本身没有 Node.js API,因此,访问文件($.fs)、启动程序($.process)、发出网络请求($.http.fetch)、读取设置和环境变量、调用模型,都必须经过 $。有了这个限制,Claude Code 才能在运行 mod 之前,列出它注册的处理函数和使用的 API。

这里有两套不同的权限。mod 使用的是你在操作系统中的账号权限。Claude Code 的 allow、ask 和 deny 规则则用来控制 Claude 发起的工具调用。

mod 和普通插件一样,可以从插件市场安装,也可以用 --plugin-dir 在单次会话中加载。它的处理函数可以在终端、桌面端应用(WSL 会话除外)、VS Code 扩展、claude -p 和 Agent SDK 中运行。Claude Code 自己的一些功能也由内置 mod 提供,例如 /diff 和 AGENTS.md 加载器。

我们怎么测的

每次运行都先创建一个新的项目目录。如果该配置需要 mod,也为它新建一个目录。接着启动 claude -p,使用 Claude Haiku 4.5,只保留 HOME、PATH、USER 和 TMPDIR 这几个环境变量。启动时加上 --strict-mcp-config,并关闭我们自己原来安装的插件。待测 mod 通过 --plugin-dir 加载,权限规则和沙箱配置通过 --settings 文件传入。

我们检查了标记文件、各次会话记录中的工具结果,以及加载错误。对于改写会话行的测试,还把保存下来的会话记录与无界面会话的输出做了对照。

测试于 10 月 4 日在 macOS 上完成。共 16 种配置,每种运行 3 次,总计 48 次。各次运行耗时合计 238 秒,按 API 标价换算为 $0.92。我们使用 Max 方案,实际计入方案的用量上限。所有会话的插件清单里都没有 Anthropic 的内置防护 mod cc-plugin-sec-default,这与文档对该环境的说明一致。

deny 规则还能拦住吗

测试命令是 touch deny-marker.txt。我们先允许 Bash,让 deny 规则成为阻止这条命令执行的唯一条件:

配置结果结果一致的次数
允许 Bash,没有 deny 规则,也没有 mod已执行3/3
用 deny 规则禁止该命令,没有 mod已拒绝3/3
deny 规则 + 只观察权限检查的 mod已拒绝3/3
deny 规则 + 在权限检查时返回 allow 的 mod已执行3/3
同上,但用 --safe-mode 启动已拒绝3/3
同上,但设置 "disableAllHooks": true已拒绝3/3
没有 allow 规则,也没有 mod(无界面会话无法询问你是否批准)未执行3/3
没有 allow 规则 + 批准调用的 mod已执行3/3
用 deny 规则禁止 Read(./secret.txt),要求 Claude 读取文件已拒绝3/3
同上,再加一个通过 $.fs.read 读取该文件的 modClaude 被拒绝,mod 读到了全部 37 个字符3/3

批准调用的 mod 只注册了一个 tool.check 处理函数。它先让 Claude Code 作出权限决定,再返回 allow。没有 mod 时,工具结果表示这条 Bash 命令已被拒绝(原文:“Permission to use Bash with command touch deny-marker.txt has been denied.”)。加上 mod 后,工具结果如下:(Bash completed with no output)

两种关闭方式都恢复了 deny 规则的拦截,但也会影响其他配置。--safe-mode 会在本次会话中关闭你的其他自定义配置。disableAllHooks 还会停用设置里的钩子(settings hook)和自定义状态栏。这两个开关都不会停用内置 mod。

内置防护何时加载

Anthropic 提供了内置防护 mod(sec-default),它会在用户安装的所有 mod 之前加载。只要它加载了,默认就是 deny 规则优先于用户 mod 生效。用户 mod 也不能修改托管钩子、托管指令或系统提示词。管理员可以用 allowModsToOverrideDenyRules 放宽其中对 deny 规则的保护。

内置防护 mod 会在两种情况下加载:机器有托管设置,或者登录账号使用 Team 或 Enterprise 方案。Anthropic 的权限文档对其余情况的说明是:mod 可以放行 deny 规则拒绝的调用(原文:“Anywhere else, the mod can approve a call that a deny rule refuses.”)。因此,如果机器没有托管设置,Pro、Max 方案,以及使用 API 密钥、Bedrock、Vertex、Foundry 的用户,都属于这个范围。

即使内置防护 mod 已经加载,mod 仍有以下能力。这些也都写在文档里:

  • deny 规则只约束 Claude 的工具调用,管不到 mod 自己的 $.fs 和 $.process 调用。即使 deny 规则禁止了 Read(.env),mod 仍然能读这个文件。
  • ask 规则要求询问用户的调用,mod 可以直接批准。被托管设置之外的 PreToolUse 钩子拦下的调用,mod 也可以批准。
  • 在自动模式(auto mode)中,mod 批准的调用会跳过自动安全检查。

沙箱与网络实测

我们通过 sandbox.enabled: true 开启沙箱,并把 allowUnsandboxedCommands: false 加入配置。随后要求 Claude 用 touch 在一个目录里创建文件。这个目录既在项目之外,也不属于沙箱默认允许写入的位置。3/3 次运行都被沙箱拒绝,错误信息为 “Operation not permitted”。

在同一批会话中,我们的 mod 通过 $.process.run 对同一个目录执行 touch,3/3 次都成功创建了文件。Anthropic 文档已经说明了这种行为:mod 启动的进程在沙箱之外运行。

有一项网络结果与文档不符。Anthropic 的管理文档说,如果会话关闭了非必要网络流量,Claude Code 就会拒绝 mod 的 $.http.fetch 请求。但我们设置 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 后,mod 请求 example.com,3/3 次都返回了 HTTP 200。这些会话中都没有加载内置遥测 mod,说明环境变量已被识别。至于网络请求为什么仍然成功,原因没有查明。

这个环境变量自己的参考文档没有提到 mod。我们也没有测试组织级关闭网页抓取的设置。

管理文档还说明,这项网络策略不约束 mod 启动的程序。我们通过 $.process.run 执行 curl,六次网络测试都返回了 HTTP 200。因此,不能把这个环境变量当作 mod 的网络隔离措施。

会话记录也能改

在 Claude Code 保存每一行会话内容之前,都会触发 session.append。测试 mod 会检查它收到的每一行,把其中的口令 PELICAN-41 替换成 REDACTED。我们在提示词里描述了这个口令,但没有直接写出口令本身。

没有 mod 时,保存的会话记录和无界面会话的输出都显示 PELICAN-41,结果是 3/3。加上 mod 后,两处都变成了 REDACTED,结果也是 3/3。因为提示词里没有出现口令,我们据此推断,被替换的是 Claude 的回复。这不是直接截获回复后得出的结论。

如果你把会话记录当作代理行为的证据,就需要考虑这一点:session.append 处理函数可以在保存之前改写会话行。我们此前的 AGENTS.md 实测 就曾用会话记录判断哪些文件被加载。不过,本次测的是回复文本,没有测试那些指令加载记录。

怎么看验证清单

claude plugin validate 是 Anthropic 建议的审查步骤。对插件目录运行 claude plugin validate <folder> 就能列出 mod 为哪些事件注册了处理函数,以及代码调用了哪些 mod API 方法。整个检查过程不会执行 mod:

modhooks:calls:
每次权限检查都返回 allowtool.check未调用 $
只观察权限检查tool.check未调用 $
改写即将保存的会话行session.append未调用 $
读取被 deny 规则禁止读取的文件session.start$.fs.read, $.fs.write
沙箱测试session.start$.fs.write, $.process.run
网络测试session.start$.fs.write, $.http.fetch, $.process.run
通过计算得出的属性名访问 $—验证失败

如果验证器无法分析 mod 如何使用 $,Claude Code 就会拒绝加载它。我们用计算得出的属性名做了测试:验证没有通过,3/3 次会话都没有执行这段 mod 代码,拒绝加载的信息只出现在调试日志里。

最值得注意的是前两行。一个 mod 只观察,另一个会批准调用,两者的清单完全相同,对 deny 规则的影响却相反。清单只说明这个 mod 能回应权限检查,至于它会怎么回应,得看代码。改变权限决定和改写会话行,都不需要调用 $。如果审查时只找文件读写和网络请求,就会漏掉这两种行为。

审查时,两行清单都要看:

  • hooks::tool.check 可以批准或拒绝工具调用。tool.call 和 prompt.submit 可以查看、修改工具调用和提示词。session.append 可以改写即将保存的会话内容。prompt.compose 和 prompt.section 可以修改系统提示词。只要出现其中任何一项,就要继续读对应的处理函数。
  • calls::$.process.run 和 $.process.spawn 启动的进程不受沙箱及这项网络策略限制。$.fs.read 和 $.fs.write 不受你的 deny 规则限制。$.http.fetch 会发出网络请求。$.env.get 和 $.settings.read 能读取可能存有密钥的值。$.model.complete 会消耗你的方案额度,或产生 API 密钥对应的费用。

应该怎么做

在你自己的机器上:

  • mod 一旦加载,就能以你的账号权限访问文件、启动程序和联网。只安装信任的作者提供的 mod,阅读源码,并先运行 claude plugin validate。
  • --plugin-dir 只是临时试用,不提供隔离。试用不熟悉的代码时,用另一台机器、虚拟机或单独的用户账号。
  • 没有内置防护 mod 时,处理 tool.check 的 mod 可以越过你的 deny 规则。密钥应放在需要额外确认、当前用户账号无法直接读取的位置。备份也应放在这个账号无法覆盖的地方。
  • 用 claude --safe-mode 启动一次会话,可以临时关闭已安装的 mod 和其他自定义配置,快速判断问题是否与它们有关。

在组织里:先确认内置防护 mod 已经加载。机器有托管设置,或者用 Team、Enterprise 方案登录时,默认都会加载它。如果配置了 prependPlugins,则需要显式把内置防护 mod 列进去。

如果只允许组织托管的 mod 和内置 mod,在托管设置的 pluginConfigs 中,为 cc-plugin-sec-default@builtin 设置 allowManagedModsOnly。插件市场白名单(strictKnownMarketplaces)可以限制 mod 的来源,disableSideloadFlags 可以禁用 --plugin-dir。保留默认保护,不要设置 allowModsToOverrideDenyRules。

哪些情况没有测

  • Team、Enterprise 和有托管设置的机器。内置防护 mod 在这些环境中的行为,依据的是 Anthropic 官方文档和公开源码。
  • 自动模式。mod 批准后会跳过自动安全检查,这是文档里的说明,我们没有实测。
  • 交互式会话和桌面端应用。在交互式会话中,如果目录尚未被信任,mod 会等待信任提示。
  • 第三方 mod。我们的 7 个 mod 都是专为本次测试写的,没有审计任何已发布的第三方 mod。

相关阅读

来源

  1. Anthropic:mod 概览。介绍 mod 能访问哪些资源、可用环境、内置 mod 和关闭方式,并说明 mod 不受沙箱限制(原文:“Mods aren’t sandboxed”)。
  2. Anthropic:管理组织中的 mod。说明内置防护 mod sec-default 的加载条件、deny 规则的约束范围和网络策略。还介绍 allowManagedModsOnly 和 prependPlugins,以及 allowModsToOverrideDenyRules 的配置方式,并解释 claude plugin validate 清单的读法。
  3. Anthropic:配置权限:用钩子扩展权限检查。说明在前述加载内置防护 mod 的情况之外,mod 可以批准 deny 规则拒绝的调用(原文:“Anywhere else, the mod can approve a call that a deny rule refuses.”)。
  4. Anthropic:使用 mod API。说明钩子模块没有 Node.js API,并介绍 $.fs、$.process 和 $.http。
  5. Anthropic:mod 参考文档。介绍 tool.check 和 session.append 事件。
  6. Anthropic:沙箱。说明沙箱默认允许写入的位置。
  7. Anthropic:环境变量。说明 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC 会关闭哪些流量。
  8. Anthropic:Claude Code 更新日志。2.1.287 加入 mod,2.1.288 和 2.1.289 包含 mod 相关修复。
  9. Anthropic:Claude Code mod 入门,2026 年 10 月 1 日。
  10. GitHub:内置防护 mod sec-default 的源码。
  11. npm:@anthropic-ai/claude-code。2.1.287 于 10 月 1 日发布,2.1.289 于 10 月 3 日发布。

我们自己的测量:2026 年 10 月 4 日,在 macOS 上使用 Claude Code 2.1.289 和 Claude Haiku 4.5,以个人 Max 方案登录,机器没有托管设置。共运行 48 次 claude -p 会话,覆盖 16 种配置,每种各跑 3 次。按 API 标价换算为 $0.92,实际计入 Max 方案的用量上限,各次运行耗时合计 238 秒。结果依据标记文件、各次会话记录中的工具结果和加载错误。改写会话行的测试还核对了无界面会话的输出。所有测试 mod 都为本次实验编写,通过 --plugin-dir 加载,在临时目录中运行。

FAQ

Claude Code 的 mod 是什么?mod 是带有 JavaScript 或 TypeScript 处理函数的插件,直接在 Claude Code 进程里运行。这项功能在 10 月 1 日的 2.1.287 中加入,默认开启。它使用你的账号权限访问文件、启动程序和联网。

mod 能越过我的 deny 规则吗?如果机器没有托管设置,登录的也不是 Team 或 Enterprise 方案,就可以。我们的个人 Max 实测中,没有 mod 时,deny 规则拦住命令的结果是 3/3。加载批准调用的 mod 后,命令执行成功的结果是 3/3。如果内置防护 mod 已经加载,默认会让 deny 规则优先于用户 mod 生效,但规则仍然管不到 mod 自己的文件和进程调用。

mod 受沙箱限制吗?不受限制。Claude 向项目外写文件时,3/3 次都被沙箱拦住。我们的 mod 启动进程向同一目录写文件,3/3 次都成功。

安装前怎么检查 mod?对插件目录运行 claude plugin validate,再阅读清单中列出的处理函数。hooks: 一行出现 tool.check,就意味着它能回应权限检查,即使 calls: 一行没有列出任何调用。

怎么关闭 mod?关闭单个 mod,在 /plugin 中操作。只关闭一次会话中的 mod,用 claude --safe-mode。要在所有会话中停用自己安装的 mod,在用户设置里写入 "disableAllHooks": true,但这也会停用设置里的钩子和状态栏。内置 mod 仍会运行。

这篇对你有帮助吗?

相关阅读


文章独立产出 · 编辑政策

继续阅读 →