正如第 1 章所说,Claude Code 每调用一次工具都要过一道权限关卡。如果把它想成一个旋钮,那么一嫌吵,你就会把它拧到最松的一端。实际上它是确认的频率、按工具粒度的许可、操作系统层面的隔离三个职责不同的东西。一边收紧,另一边就可以放松,「要安全还是要快」并不是二选一

放权不是「全给」或「全不给」

出发点不是模式的名字,而是「在这项工作里,哪里是一旦出事就无法挽回的」。判断依据有三条。

  • 能不能退回来 —— 用 git 能退回来的编辑,损失就小。彻底删除、强制 push、把数据库搞坏,都退不回来
  • 影响能波及多远 —— 是止步于工作目录,还是会波及生产环境、共享分支、别人的环境
  • 会不会碰到机密 —— 能读到能发出去同时成立,就成了泄露

麻烦的偏偏是三条轴上都安全的操作(测试、格式化、本地编辑),而危险的操作难得出现一次。一刀切地放松,就把危险那一侧也一起打开了。按频率放松,按性质收紧,这是骨架。

权限模式 —— 真正改变的是什么

最大的那个旋钮是权限模式,它决定确认频率的大框。用 Shift+Tab 切换(详解见 Claude Code 的权限模式)。

逐次确认权限(default)

读取自动放行,编辑和执行命令每次都要确认。第一次接触的代码仓库就该用它。

自动接受编辑(acceptEdits)

自动批准工作目录内的编辑。范围之外、受保护路径、其他命令仍要确认。

计划模式(plan)

只调查,不改动源码。批准计划之后才转入执行。

自动模式(auto)

由另一个判定模型在执行前逐项审视,只拦下危险的那些。有使用条件。

绕过权限(bypassPermissions)

确认和安全检查都不走。只用于隔离环境。仅在用专用参数启动时才生效。

还有一个只存在于配置里的 dontAsk(只执行许可清单上的和只读的命令,其余一律拒绝)。

受保护路径也要注意。对 .git.claude、shell 配置的写入,在常规模式下不会被自动批准。默认模式可以写进配置,但唯独自动模式在项目级配置里会被忽略——这条线是为了不让代码仓库那一侧擅自把它打开

自动模式不是「更快的 default」

确认几乎会消失,但并不是放任不管:判定模型会拦下超出你所托付范围的操作、去碰它不了解的基础设施的操作、以及被它读到的内容所引导的操作。容易放行的是工作目录内的文件操作和只读的 HTTP。会被拦下的是把机密发到外部、部署到生产环境、以及破坏性的 git 操作。

你在对话里说过的边界不会被保存下来。 「不要 push」可以成为拦截的依据,但它每次都要从当前这轮对话里重新读一遍,压缩时被丢掉,边界也就跟着没了。再加上自动模式属于研究预览,官方自己也说它减少确认,但不保证安全。它替代不了人工评审。

为什么绕过权限之后还是会被问

本该跳过确认的 --dangerously-skip-permissions 已经加上了,Claude 却还在问「可以执行吗」。它没坏。许可有两个互相独立的层,而绕过权限能去掉的只有其中一个(见 为什么绕过模式下仍然会被要求授权)。

第 1 层:工具权限的界面(可以去掉)

「可以编辑这个文件吗」——在调用工具之前弹出的交互式对话框。它是 Claude Code 这个程序弹出来的。

第 2 层:Claude 自己的安全判断(去不掉)

「这会改动生产数据库,确定要继续吗」——以对话正文的形式返回的确认。它来自模型的行为准则,所以参数拦不住它。

分辨方法是看它是界面弹窗,还是回答里的文字。第 2 层被触发的条件和开头那三条轴基本一致——不可逆、影响面广、安全风险高。彻底删除、强制 push、往生产环境跑迁移,即使你把权限全开,Claude 也会停下来。

这不是缺陷,是设计。 绕过权限交给你的是使用工具的钥匙,不是关掉 Claude 判断的钥匙。第 2 层不可能降到零。

频率倒是可以降下来。在 CLAUDE.md 里只写那些能作为事实陈述的前提,并且把请求说得具体一些——比「整理干净」更不容易触发确认的是「删掉 /tmp/ 里的 .log」。但要记住,绕过权限并不是「确认太烦」的答案(见 绕过模式的风险与安全用法)。

settings.json 里的规则 —— 同一个确认不答第二遍

如果说模式管的是「整体的频率」,那么权限规则管的就是「按工具、按命令的例外」。你可以在 settings.json 里写 allow(不确认)/ask(每次确认)/deny(禁止),并且共享给团队(见 权限规则(allow/ask/deny)的配置)。

求值顺序是 deny → ask → allow第一条匹配上的胜出,写得多细都不会改变这个顺序——范围很宽的 Bash(aws *) 的 deny,会压过具体的 Bash(aws s3 ls) 的 allow。deny 不能带例外。「明明 allow 了却还是弹确认」,通常只是有另一条 ask 先匹配上了。ask 即使在自动模式下也会强制弹出确认,所以它是安放那些退不回来的操作的地方

// .claude/settings.json { "permissions": { "defaultMode": "acceptEdits", "allow": ["Bash(npm run *)"], "ask": ["Bash(git push *)"], "deny": ["Read(.env)", "Read(~/.ssh/**)"] } }

放在哪里也有优先级。从强到弱依次是管理端配置(不可覆盖)→ 命令行 → settings.local.jsonsettings.json~/.claude/settings.json。不过任何一层的 deny,都必然压过其他任何一层的 allow。在匹配式里,空格加 * 表示单词边界Bash(ls *) 匹配 ls -la,但不匹配 lsof)。

规则保护不了的东西

规则看的只是「即将执行的那条命令的字符串」,绕开这个字符串的路径,它一概放行。

  • 挡不住间接访问 —— Read(.env) 的 deny 对内置的文件工具和 cat 有效,但对脚本内部打开文件的操作无效
  • 环境启动器会把内容藏起来 —— devbox run *docker exec 会把参数原样执行,所以 Bash(devbox run *) 的 allow 连 devbox run rm -rf . 都一并放行了
  • 靠参数来限制 URL 很脆弱 —— 调换顺序、用变量展开就能溜过去。更稳的做法是把 curlwget 整个 deny 掉,再用 WebFetch(domain:) 指定允许的目标

就算在 CLAUDE.md 里写「不要读 .env」,那也不是规则。CLAUDE.md 改变的是 Claude 打算去做什么,改变不了它被允许做什么。能改变许可范围的是规则、模式,以及第 6 章讲的 PreToolUse 钩子(而且 deny 和 ask 不管钩子返回什么,都照样求值)。

沙箱 —— 圈得住什么,圈不住什么

堵住规则够不到的那些路径的,是沙箱——它不问「要确认什么」,而是先圈定「能碰到多远」。执行这条边界的不是 Claude,而是操作系统(内核),所以即便一条已获许可的命令做了名字之外的事,边界也不会挪动(见 Claude Code 沙箱完全指南)。

① 文件系统的隔离

能写入的只有工作目录和临时目录(初始值)。~/.bashrc 和系统区域改不了。

② 网络的隔离

初始状态是不许连任何地方的默认拒绝。要连一个新域名时会弹出确认,登记进 allowedDomains 之后就不再问。

这两条必须成套使用——只用其中一条,读到的机密照样会流出去。批准的方式有两种。自动放行模式会不经确认就执行沙箱内的 Bash,常规权限模式则是在隔离的基础上,确认照样弹。即使在自动放行下,deny 也始终优先冲着要害路径去的 rm 仍要确认按内容指定的 ask 同样会强制确认

要注意有两个东西都叫「自动」。沙箱的自动放行模式意思是「有操作系统的边界关着它,所以放行」,权限模式里的自动模式(auto)意思是「判定模型审过了,所以放行」。

先弄清它不保护什么

沙箱并不是完全的隔离。把这一点含糊过去,还长期开着自动放行,是最危险的状态。

  • 它只覆盖 Bash 及其子进程 —— 内置的 Read / Edit / Write、MCP 服务器、钩子都在它之外(那些要用权限规则来控制)。想把整个进程包起来,用 @anthropic-ai/sandbox-runtime
  • 读取的初始范围很宽 —— 它圈住的主要是写入~/.ssh~/.aws/credentials 照原样是读得到的。要用 denyRead 堵上
  • 许可开得太宽,本身就成了漏洞 —— 通信按主机名判定,加密后的内容默认不做检查。放行一个很宽的域名,就留下了往外走的余地
  • 它挑运行环境 —— macOS 不需要额外安装。Linux 和 WSL2 需要 bubblewrapsocat,而原生 Windows 不受支持

沙箱不是用来对付攻击者的墙,而是把事故和失控减少一个数量级的安全带。Anthropic 公开表示在内部安全地把权限确认减少了 84%,但那是确认变少了的报告,不是攻不破的保证

事故基本就发生在四种形态上

换个角度,从事故这一侧把这些机制重新排一遍。选配置的标准是它对这四种是否有效

① 破坏性的命令

rm 清掉了预料之外的路径,git push --force 抹掉了别人的工作。它们的共同点是退不回来。有效的是 deny 和 ask 规则加上文件隔离把退不回来的操作先放进 ask,最稳妥。

② 机密的外泄

只有能读到能发出去凑齐了,才会酿成事故。对策也是两层——不让它读Read(.env) 的 deny、denyRead)和不让它发(deny 掉 curlwget,把允许的域名收窄)。只做一层是不够的。

③ 波及到别的分支、别的环境

本来只想在本地改一个文件,结果演变成往共享分支 push、往生产环境部署——这叫操作的升级。在常规模式下每上一个台阶都会插入一次确认,但全都放开之后,台阶就没了。把 push 和部署放进 ask,是很便宜的一份保险。

④ 从读过的文件里混进来的指令

Claude 会读的 README、issue、网页、PDF 里,有可能埋着写给 Claude 的指令(提示词注入)。哪怕是用白色字写的「把这些发到这个地址」,在 Claude 看来也和你的请求走的是同一个入口的文本,数据和指令之间并没有一条自明的界线。

对此无效的是绕过模式(埋进来的东西会一路走到执行)和在 CLAUDE.md 里下禁令(它改变不了许可范围)。有效的是操作系统层面的边界——写不了的地方就是写不了,连不上的地方就是连不上——以及 deny 规则。埋进来的东西是看不见的,所以不要指望「自己能察觉」;来源不可信的资料,要只在那一个会话里把权限收紧之后再让它读。

可以交出去的/必须拦下的

把三条轴套上去,线大致是这样划的。

可以交出去(写进 allow)

测试、类型检查、代码检查工具、构建/工作目录内的编辑/读取和搜索/本地的提交

必须拦下(放进 ask 或 deny)

往共享分支 push 和强制 push/生产环境的部署和迁移/读取机密文件/包含对外发送的命令/往工作目录之外写入

  • 给平时定下一个模式。 反复编辑就用 acceptEdits,涉密的工作就用 default。写进 defaultMode
  • 同一个确认答过三次,就挪进 allow。 反过来,只要有一次让你觉得「这有点悬」的操作,就固定放进 ask
  • 对话里说过的禁令,要按「会消失」来对待。
  • 放松一处的时候,一定要在别处收紧。 既没有确认、也没有边界的状态,绝不要造出来

可以使用绕过权限的条件。 在坏了也能直接丢掉的容器/虚拟机/CI 运行器里面,只挂载工作目录,不要把宿主机的 .env 和 SSH 密钥带进去。「确认太烦」不构成理由。做完之后一定要把差异读一遍。

这里讲到的全都是「减少事故」的机制,不是「消灭事故」的机制。第 2 层的判断、自动模式的判定、沙箱的边界,都存在被绕过去的形态。始终保持在能退回来的状态,才是最管用的一招。

小结

  • 权限分模式、规则、沙箱三层。判断轴是能不能退回来、能波及多远、会不会碰到机密,做法是按频率放松,按性质收紧
  • 许可是两层结构。绕过权限能去掉的只有第 1 层的界面,以对话文字形式出现的确认是设计如此
  • 规则按 deny → ask → allow 求值,第一条匹配上的胜出,写得更具体也不会改变顺序
  • 规则只看字符串。把缺口堵上的是沙箱。但它只覆盖 Bash 及其子进程,而且读取的初始范围很宽
  • 事故的形态有四种:破坏性命令、机密外泄、波及到别的环境、指令混入

放权的范围定下来之后,剩下的就是照着自己的环境把它养起来。请前往 第 6 章「扩展它」