最近 X 上有一组数据挺扎眼:Matt Hager 扫描了 GitHub 上约 1.6 万份公开的 AI coding agent 配置,发现设置了权限的 Claude Code 配置里,85% 一条 deny 规则都没有。

数据为原帖作者自述,我没有独立复核。
换句话说,大多数人的配置只写了“允许什么”,没写“绝不允许什么”。这篇文章就做一件事:给出一份能直接复制的 Claude Code 权限配置,讲清楚它为什么这样写、哪里挡不住,以及怎么用沙箱补上。 最后附一张 Codex 的对照表。
文中所有配置项都按 Claude Code 官方权限文档和沙箱文档核对过(2026 年 10 月版本)。Claude Code 更新很快,以官方文档为准。
一、先抄这份:项目级 .claude/settings.json
在项目根目录新建 .claude/settings.json:
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(git push *)",
"Bash(curl *)",
"Bash(wget *)"
],
"ask": [
"Bash(rm *)",
"Bash(git reset *)"
],
"allow": [
"Bash(npm run *)",
"Bash(git commit *)"
],
"disableBypassPermissionsMode": "disable"
}
}

逐段解释:
- deny:不读
.env和secrets/下的文件,不推代码,不用curl/wget直接联网。Read的 deny 规则同时会阻止 Edit 和 Write 写这些路径。 - ask:删除和
git reset这类不可逆操作,每次都弹窗确认。 - allow:跑 npm 脚本、提交本地 commit 不用每次点确认,减少审批疲劳。
disableBypassPermissionsMode:禁止切到bypassPermissions模式,避免“嫌弹窗烦就一键全放开”。
Bash(git push *) 末尾的 * 也会匹配不带参数的 git push。如果项目里有需要给 Claude 读的 .env.example,可以在 deny 列表里 Read(./.env.*) 之后加一条 Read(!.env.example) 把它豁免出来(gitignore 式的 ! 取反,只对同一个设置文件里排在它前面的规则生效)。
改完后在 Claude Code 里输入 /permissions,能看到每条规则以及它来自哪个 settings 文件。deny / ask 规则里的工具名拼错了,启动时会有警告;被跳过的无效规则也会出现在 claude doctor 的输出里。
二、三个配置文件,分别放什么
Claude Code 会同时读取多层设置:
| 文件 | 作用范围 | 适合放什么 |
|---|---|---|
~/.claude/settings.json |
当前用户的所有项目 | 个人通用的 deny(如 Read(~/.ssh/**))、沙箱开关 |
.claude/settings.json |
当前项目,可提交到 Git | 团队共享的项目规则,就是上面那份 |
.claude/settings.local.json |
当前项目,仅本机 | 个人临时放行;弹窗里点 “Yes, and don’t ask again” 时,规则会自动存到这里 |
| 托管设置(managed settings) | 组织统一下发 | 强制开沙箱、禁用 bypass,用户和项目都覆盖不了 |
两点值得记住:
- deny 在任何一层都赢。 用户设置里 allow、项目设置里 deny,结果是 deny;反过来也一样。
- 项目里的 allow 要先信任工作区才生效。 打开一个陌生仓库时,它
.claude/settings.json里的 allow 规则会列在工作区信任对话框里,你接受之后才生效;deny 和 ask 只会收紧权限,所以始终生效。
另外,建议定期打开 .claude/settings.local.json 看一眼。点“不再询问”攒下来的规则都在这里,时间长了很容易积累出比你以为的更宽的放行。最近也有人专门讨论过 “allow similar” 这类按钮本身就是攻击面。
三、规则怎么匹配:deny → ask → allow

官方文档写得很明确:规则按 deny → ask → allow 的顺序检查,先命中谁就听谁,规则写得多具体不改变顺序。所以:
deny: Bash(aws *)会挡住allow: Bash(aws s3 ls),allow 没法在 deny 里“开口子”;- 同理,命中 ask 的调用,就算有更具体的 allow,也照样弹窗。
规则语法速查:
| 写法 | 含义 |
|---|---|
Bash 或 Bash(*) |
所有 Bash 命令;放在 deny 里会让 Claude 完全看不到这个工具 |
Bash(npm run build) |
只匹配这一条完整命令 |
Bash(npm run *) |
npm run 开头的所有命令,包括不带参数的 npm run |
Read(./.env) |
当前目录下的 .env |
Read(//**/.env) |
整个文件系统里的任何 .env(// 开头才是绝对路径) |
WebFetch(domain:example.com) |
对 example.com 的抓取请求 |
mcp__github__* |
github 这个 MCP 服务器的所有工具 |
mcp__* |
所有 MCP 工具(只能用在 deny / ask) |
写 Bash 规则时,把 * 放在子命令后面:Bash(git log *) 只放行 git log,而 Bash(git *) 会放行所有 git 命令。Claude Code 还能识别 &&、||、;、| 等分隔符,Bash(safe-cmd *) 不会顺带放行 safe-cmd && other-cmd。
没命中任何规则的调用,交给权限模式决定:
| 模式 | 行为 |
|---|---|
default(Manual) |
编辑文件、运行命令、联网等大多数操作前询问 |
acceptEdits |
自动接受工作目录内的文件编辑,以及 mkdir、touch、rm、mv、cp、sed 等常见文件命令 |
plan |
只读探索,不改源码 |
auto |
由另一个分类器模型审查动作,替代日常弹窗;显式 ask 规则照样弹窗 |
dontAsk |
本该询问的一律拒绝,只执行预先 allow 的 |
bypassPermissions |
跳过权限提示,官方建议只在容器或虚拟机里用 |
想改默认模式,在设置里写 permissions.defaultMode。注意 acceptEdits 会自动放行 rm,这也是我在第一节把 Bash(rm *) 放进 ask 的原因:显式的 ask 规则在各模式下都会照样弹窗。deny 规则则在所有模式下都生效,包括 bypassPermissions。
四、deny 规则挡不住什么:6 个常见坑
这部分是我觉得最值得读的。权限规则由 Claude Code 在工具执行前判定,它很有用,但不是安全边界。
1. Bash 规则按命令文本匹配,换个写法就绕过了。 官方文档自己列了反例:Bash(curl *) 挡得住 curl https://example.com,挡不住 /usr/bin/curl ... 或 sh -c 'curl ...';Bash(git push *) 挡不住 git -C . push origin main。需要真正硬的限制,靠下一节的沙箱。
2. Read 的 deny 挡不住脚本自己去读文件。 它覆盖 Claude 的内置文件工具、cat / head / tail / sed 等能识别的命令和重定向,但一个自己打开文件的 Python 或 Node 脚本不受约束。
3. .claudeignore 没用。 文档原话是它“has no effect”,要把里面的条目改写成 Read deny 规则。
4. Write(path) 规则永远不会匹配。 文件写入只按 Edit(path) 和 Read(path) 判定。想禁止写 docs/,要写 Edit(docs/**)。
5. /path 不是绝对路径。 单斜杠开头锚定在“设置文件所在的位置”:写在用户设置里的 Read(/secrets/**),挡的是 ~/.claude/secrets/**,不是项目里的 secrets。绝对路径要写 //,家目录写 ~/。
6. 写在 CLAUDE.md 里的“不要读 .env”不是限制。 它只影响 Claude 想做什么,不改变 Claude Code 允许什么。我在 Day 13 写 AGENTS.md 时也说过:项目规则是一条模型指导,不是不可绕过的权限边界。
五、用沙箱补上 OS 级的那一层

沙箱由操作系统强制执行(macOS 用 Seatbelt,Linux / WSL2 用 bubblewrap),限制 Bash 命令及其子进程能读写的文件和能连的网络。不管命令怎么写都生效,正好补上第四节的前两个坑。
开启步骤:
Linux / WSL2 先装依赖(macOS 不需要):
# Ubuntu / Debian
sudo apt-get install bubblewrap socat
然后在 Claude Code 会话里运行:
/sandbox
在 Mode 页选择 auto-allow(沙箱内命令免确认)或 regular permissions(沙箱内也照常弹窗)。想对所有项目生效,在 ~/.claude/settings.json 里写:
{
"sandbox": {
"enabled": true,
"allowUnsandboxedCommands": false,
"credentials": {
"files": [
{ "path": "~/.aws/credentials", "mode": "deny" },
{ "path": "~/.ssh", "mode": "deny" }
],
"envVars": [
{ "name": "GITHUB_TOKEN", "mode": "deny" }
]
},
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
}
allowUnsandboxedCommands: false:命令在沙箱里失败后,不允许 Claude 申请到沙箱外重跑(/sandbox里显示为 Strict sandbox mode);credentials:沙箱默认能读机器上的大部分文件,包括~/.ssh和~/.aws/credentials,这里显式禁止读取,并把GITHUB_TOKEN从沙箱命令的环境变量里去掉;network.allowedDomains:沙箱命令没有直接出网的路,所有连接都经过本机代理按这份域名列表检查,列表默认为空。
注意 SSH:在 macOS 上,基于 SSH remote 的 git fetch / pull / push 在沙箱里本来就会失败,官方建议把 remote 换成 HTTPS;在 Linux 上它能工作,但前提是密钥文件可读,而上面禁读 ~/.ssh 之后就不行了。必须保留 SSH 的话,可以把 git 的联网命令放进 excludedCommands,代价是它们会在沙箱外运行。
验证沙箱是否生效:让 Claude 运行下面两条命令。不要自己在 ! 提示符里敲,那里输入的命令通常不走沙箱,测不出效果:
touch ~/sandbox-probe
curl --noproxy '*' https://example.com
第一条应该报 Operation not permitted(macOS)或 Read-only file system(Linux),第二条应该报 Could not resolve host。如果 Claude 申请到沙箱外重试,拒绝即可。
最后要说清楚边界:沙箱只管 shell 命令。Read、Edit、WebFetch 这些内置工具,以及 MCP 服务器和 hooks,都在沙箱外运行,靠的仍然是权限规则。所以这两层要一起用,缺一不可。规则表达不了的逻辑(比如按 URL 白名单检查 Bash 命令),可以再加一个 PreToolUse hook:它在权限规则判定之前运行,退出码 2 会直接拦下这次调用,即使有 allow 规则匹配。
六、怎么选:按场景组合
| 场景 | 推荐组合 |
|---|---|
| 日常本地开发 | default 模式 + 第一节的 deny / ask / allow + 沙箱 auto-allow |
| 嫌弹窗太多 | acceptEdits + 沙箱;不要直接上 bypassPermissions |
| 只想让它读代码、出方案 | plan 模式 |
| 无人值守的长任务 | 跑在容器或虚拟机里,再考虑 bypassPermissions;宿主机上不要这么做 |
| 团队统一规范 | 项目 .claude/settings.json 提交进仓库;需要强制的部分放托管设置,并配 disableBypassPermissionsMode |
在陌生仓库里跑 claude -p |
加 --setting-sources user,不读该仓库自带的设置文件和 .mcp.json |
七、Codex 对照:思路一样,默认值不同
如果你同时用 Codex,它的两个核心配置是 sandbox_mode(技术上能做什么)和 approval_policy(什么时候要问你)。写在 ~/.codex/config.toml:
approval_policy = "on-request"
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = false
这就是 Codex 官方的 Auto 预设:工作区内可读写、可运行命令,越出工作区或需要联网时询问。命令行等价写法是 codex --sandbox workspace-write --ask-for-approval on-request。注意 approval_policy = "untrusted" 已经退役,旧配置里有这一行可能导致启动失败。
| Claude Code | Codex | |
|---|---|---|
| 配置文件 | ~/.claude/settings.json、.claude/settings.json、.claude/settings.local.json |
~/.codex/config.toml |
| 细粒度工具规则 | permissions.allow / ask / deny |
以 sandbox_mode + approval_policy 为主 |
| OS 沙箱默认 | 默认关,用 /sandbox 或 sandbox.enabled 开启 |
默认开,workspace-write,网络默认关 |
| 全放开 | bypassPermissions / --dangerously-skip-permissions |
--sandbox danger-full-access / --yolo |
| 默认受保护路径 | .git、.claude、.vscode、.idea、.husky 等,写入需确认(bypass 模式除外) |
可写根目录下的 .git、.agents、.codex、.aws 为只读 |
| 自测沙箱 | 让 Claude 运行 touch ~/sandbox-probe |
codex sandbox linux [COMMAND]...(macOS 为 codex sandbox macos) |
来源:Codex Agent approvals & security。
最大的差别在默认值:Codex 默认就有 OS 级沙箱,Claude Code 默认没有,但给了更细的规则语法。 所以用 Claude Code 时,“写 deny + 开沙箱”这两步都得自己做。
八、我的看法:Agent 跑得越久,越要先写 deny
最后说点观点。
这周 X 上热门的 coding agent 新闻,很多都在让 Agent 跑得更久:Vercel 发布的 durable-harness 让 Claude Code、Codex 等 harness 在失败后自动恢复,官方说法是能跑 “hours, days, or months”;T3 Code 这类工具则让人在一个界面里同时管好几个 Agent。
我在 Day 12 写 Approval 与 Sandbox 时,mini harness 的授权粒度还是“整次运行”,文中也提到生产级产品通常会提供逐次确认、规则匹配和可信命令前缀。Claude Code 的 deny / ask / allow 就是这套东西的成熟版。但审批这件事有个两难:太细,人会疲劳到无脑点允许;太粗,一次授权就等于交出整个终端。Agent 能连续跑的时间越长,这个两难就越尖锐。
写 DeepSeek V4.1 Flash 接入 OMP 和 DSH 时,我也建议对删除、提交、发布这类操作设置审批;PiX 里,敏感操作审批和检查点精确回滚也是核心功能。道理都一样:模型能力决定 Agent 能做多少事,权限配置决定它出错时损失有多大。
所以我的建议很简单:先写 deny,再写 allow;先开沙箱,再谈自动化。 一个能跑一个月的 Agent,配一份一条 deny 规则都没有的配置,是我最担心的组合。
参考资料
- Claude Code Docs · Configure permissions:规则语法、匹配顺序、权限模式、设置文件优先级。
- Claude Code Docs · Configure the sandboxed Bash tool:沙箱开启、
credentials、网络白名单、验证方法与限制。 - Codex · Agent approvals & security:
sandbox_mode、approval_policy、受保护路径。 - Matt Hager:约 1.6 万份 coding agent 配置扫描(作者自述数据)。
- Karthik Bhaskar:“allow similar” 按钮是攻击面。
- Vercel:发布 durable-harness;GitHub · vercel-labs/durable-harness。
延伸阅读:如果你还在搭自己的 Agent,可以看 三种 LLM 接口:Chat Completions、Responses 与 Messages,了解工具调用在 API 层的样子;想在本地跑模型做 coding agent,可以看 2026 年 Mac 本地推理选购指南。
文中配置依据 2026 年 10 月的官方文档整理,Claude Code 与 Codex 迭代很快,版本差异请以官方文档为准。
Comments