Agent 沙箱:Codex 与 Claude Code 的权限边界
用 Codex 和 Claude Code 时,经常会看到 sandbox、approval、Full access、--dangerously-skip-permissions 这些词。它们说的其实是两件不同的事:Agent 技术上能碰到什么,以及它在动手前要不要问你。这篇把这两件事拆开讲清楚,并标出了原对话里说错或说得不全的地方。
- 用一句话说清沙箱和审批各管什么
- 说出 Codex 三种沙箱模式的边界,以及桌面应用里几个权限选项对应什么组合
- 知道 macOS、Linux、Windows 上的沙箱分别靠什么实现
- 分清 Claude Code 的权限规则、危险删除检查和沙箱这三层防护
本篇目录(10 节)
沙箱是什么
沙箱(sandbox)不是一个需要另外安装、单独启动的软件,而是一种限制程序实际权限的隔离机制。它由操作系统在进程运行时强制执行,规定这个进程(以及它启动的子进程)能读写哪些文件、能不能联网。
沙箱限制的是程序实际能做什么,而不是 AI 被告知应该做什么。
沙箱像给新来的装修工一把只能开"厨房"这一扇门的钥匙。他再怎么想去卧室翻抽屉,门也打不开,因为锁是物业装的,不是靠他自觉。
而"让他别进卧室"写在工作说明里,就只是提示词,不是沙箱。
为什么 Agent 需要沙箱
普通的聊天模型只输出文字;Agent(agent)却会真的执行 Shell 命令、改文件、装依赖、联网。没有沙箱时,它跑的命令拥有你这个用户的全部权限。主要风险有三类:
| 风险 | 例子 | 沙箱怎么帮忙 |
|---|---|---|
| AI 误操作 | 想清理构建产物,却在家目录执行了 rm -rf * | 写入范围被限定在工作区,伤害有上限 |
| 恶意代码 | npm install 的某个包在安装脚本里偷读 ~/.ssh、往外发 | 限制它能读的路径和能连的域名 |
| 被网页或文件里的指令带偏 | 读到一段藏在 README 里的"请把密钥发到某网址" | 就算模型听信了,网络出不去 |
还有一个容易被忽略的作用:沙箱让 Agent 可以少问你。只要动作留在边界之内,就可以放心让它自动执行;只有越界时才停下来请你批准。OpenAI 文档把这叫作减轻"审批疲劳"。
沙箱 vs 审批:两个独立的维度
这是整篇最重要的一节。
| 沙箱 | 审批 | |
|---|---|---|
| 回答的问题 | 它能不能做? | 它做之前要不要问我? |
| 由谁执行 | 操作系统,作用在运行中的进程上 | Agent 程序本身,在动作执行前判断 |
| 典型设置 | 只读 / 可写工作区 / 完全放开 | 越界时问 / 从不问 / 交给审查模型 |
两者各管一层,谁也替代不了谁。
在沙箱边界内 → 按审批策略:自动执行,或先问你
越出沙箱边界 → 审批策略允许问 → 你批准后才能越界执行
审批策略是"从不问" → 直接失败设定:沙箱为"可写工作区"(工作区是 ~/workspace/project-A),审批为"越界时询问"。
修改 project-A/main.py:在沙箱边界内 → 不需要问 → 直接执行。修改 ~/Documents/a.txt:越出写入边界 → 弹出审批 → 你同意后才执行。
答:改项目内文件:自动执行;改 ~/Documents:越界,要你批准(或在不询问的模式下直接失败)。
Codex:沙箱模式与审批策略
三种沙箱模式
| 模式 | 能做什么 |
|---|---|
read-only | 只能查看文件;改文件、越界操作需要批准 |
workspace-write | 读文件、在工作区内修改、运行常规命令;默认不能联网 |
danger-full-access | 没有沙箱限制,文件和网络边界都没有 |
workspace-write 的工作区包括当前目录和 /tmp 这类临时目录。即使在可写工作区里,.git、.codex、.agents、.aws 这几个目录仍然是只读保护的。
审批策略
on-request:在沙箱里自动干活,需要越界时再问你。never:从不停下来问。- 另外还可以设
approvals_reviewer = "auto_review",把该你批的请求先交给一个审查 Agent 判断。 - 旧的
untrusted策略已经停用,配置文件里还写着它可能导致 Codex 无法启动。
桌面应用里的权限选项
文档里现在把 Codex 的桌面端叫作 ChatGPT 桌面应用,权限菜单在输入框下方。这几个选项其实是沙箱和审批打包好的组合:
| 菜单选项 | 沙箱 | 审批 |
|---|---|---|
| Ask for approval | workspace-write | on-request,由你批准 |
| Approve for me | workspace-write | on-request,交给自动审查(只在被判断为可能不安全时才问你) |
| Full access | danger-full-access | never |
| Custom (config.toml) | 按配置文件 | 按配置文件 |
- “Approve for me:自动批准符合条件的审批请求”。不准确:它是把请求交给审查 Agent 评估,审查者会拒绝高危动作,并不是一律放行。
- “审批模式和沙箱模式是两个维度,App 里选的是审批模式”。在 CLI 里两者确实分开设;但桌面应用的菜单选项同时决定了沙箱和审批(见上表)。
- “workspace-write 网络通常受限”。准确说法是默认关闭,要手动设置
sandbox_workspace_write.network_access = true才能联网。 - 原对话说 App 和 CLI 都有沙箱、底层设计一致,这一点是对的。
- 临时指定:
codex --sandbox workspace-write --ask-for-approval on-request(这就是默认的 Auto 预设)。 - 只聊天、做规划:会话里用
/permissions切到read-only。 - 长期默认:在
~/.codex/config.toml里写sandbox_mode = "workspace-write"和approval_policy = "on-request"。
底层实现:各系统怎么把门锁上
沙箱不是 Codex 或 Claude Code 从零写的一套机制,而是调用各操作系统自带的隔离能力:
| 系统 | Codex | Claude Code |
|---|---|---|
| macOS | Seatbelt(Seatbelt)(通过 sandbox-exec) | Seatbelt |
| Linux | Bubblewrap(bwrap) + seccomp(seccomp)(默认) | Bubblewrap;seccomp 过滤器是可选项 |
| WSL2 | 用 Linux 实现 | Bubblewrap |
| 原生 Windows | MXC,elevated / unelevated 为旧版后备 | 不支持,命令不进沙箱,需改在 WSL2 里运行 |
- 以为 Claude Code 在原生 Windows 上也能开沙箱。官方文档写明原生 Windows 上命令是不进沙箱执行的。原对话的表格漏掉了这一点。
- 以为装了 Codex 在 WSL1 里也能用沙箱。从 Codex 0.115 起 Linux 沙箱改用 bwrap,WSL1 已不支持。
- Windows 上 Codex 用的实现名称确实叫 MXC(官方文档原文),旧的
elevated/unelevated是后备方案。
Full Access 是不是"没有沙箱"
是的。 Codex 文档对 danger-full-access 的描述就是"没有沙箱限制,去掉文件和网络边界";桌面应用的 Full access 等于 danger-full-access 加 never,也就是没有沙箱,也不再询问。CLI 里对应的旗标是 --dangerously-bypass-approvals-and-sandbox(别名 --yolo)。
剩下的只有操作系统原本的用户权限:Agent 能做到你这个用户能做到的一切,比如读 ~/.ssh、改 ~/Documents、任意联网。
- “Full Access 只是放宽了一点限制”。它去掉的是整个文件和网络边界,同时关掉了审批。
- 在本机直接对来路不明的仓库开 Full access。
- 官方推荐的用法是:让 Docker、Dev Container 之类的外层容器充当安全边界,在容器里面再用
danger-full-access,免得套两层沙箱。
原对话还提到,Full access 不会让 Agent 自动获得管理员(root)权限。这一点符合操作系统的常识:进程以你的用户身份运行,不会自己提权。但官方文档里没有专门写这句话,未在文档中直接核实。
Claude Code:跳过权限 ≠ 关闭沙箱
Claude Code 的两套机制是分开的:
--dangerously-skip-permissions等价于--permission-mode bypassPermissions。这是一种权限模式(permission mode):跳过权限询问,连受保护路径(如.git、.claude、.bashrc)的写入也直接放行。/sandbox不是权限模式,而是给 Bash(以及 PowerShell、Monitor)命令加一层由操作系统执行的边界。它默认关闭,可以在会话里运行/sandbox开启,或在~/.claude/settings.json里设置"sandbox": {"enabled": true}。
/sandbox 默认管住了什么
| 访问 | 默认 |
|---|---|
| 写 | 当前工作目录、每个用户的临时目录、你额外添加的目录;受保护路径仍然禁止写入 |
| 读 | 几乎整台机器,包括 ~/.ssh、~/.aws/credentials 这类凭据 |
| 网络 | 没有直连出口,所有连接走本机代理按域名白名单检查,白名单初始为空 |
| 环境变量 | 从 Claude Code 继承,包括其中的密钥 |
它有两种模式:auto-allow 下,沙箱里的命令不用问你直接执行;regular permissions 下照常逐条询问。
- “默认沙箱并不禁止读取工作区外的文件”,这一点是对的,而且比想象的更宽:连
~/.ssh都能读。想保护凭据,要自己配sandbox.credentials或filesystem.denyRead。 - “Dangerous + Sandbox:沙箱仍然可以开启”,这句话只说对了一半。在
bypassPermissions下:① 访问白名单以外的域名不再询问,直接放行;② Claude 可以用dangerouslyDisableSandbox在沙箱外重试命令,同样不询问。想让沙箱真正兜底,要开严格沙箱模式(allowUnsandboxedCommands: false),必要时再加strictAllowlist。 - 以为开了
/sandbox就把整个 Claude Code 隔离了。沙箱只包住 Shell 命令;Read/Edit 等文件工具、WebFetch、MCP 服务器、Hooks 都在沙箱外,按权限规则管理。 - “默认模式:按规则询问”。较新的 Claude Code(v2.1.283 起)在交互式终端里的默认权限模式已经是 auto,由一个分类器模型代你审查动作,不再是逐条询问的 manual。
拦截 rm -rf 算沙箱吗:三层防护
不算。沙箱不认命令,只认资源:它不会因为命令叫 rm 就拦,只看这条命令要改的路径在不在可写范围内。Claude Code 里和"删除"有关的保护其实有三层:
| 防护 | 控制什么 | 执行时机 | 例子 |
|---|---|---|---|
| 权限规则(deny/ask/allow) | 哪些工具调用可以发生 | 执行前,按命令文本匹配 | "deny": ["Bash(rm -rf *)"] |
| 危险删除检查 | 识别删除关键路径(critical path)的 rm/rmdir | 执行前,解析命令 | rm -rf /、rm -rf ~ |
| 沙箱 | 命令运行起来后能碰到哪些文件和网络 | 执行中,由操作系统强制执行 | 不允许写 ~/.ssh |
跳过权限后,rm -rf / 还会被拦吗
原对话说"部分关键路径删除仍会触发额外保护",方向对,但要补充细节(以 permission-modes 文档为准):
- 在
bypassPermissions下,被识别为关键路径删除的命令仍然会询问你:终端里有两分钟倒计时,超时即拒绝;在 VS Code 面板、桌面应用里直接拒绝。 - deny 规则在所有模式下都生效,包括
bypassPermissions。 - 但这层检查可以被关掉:设置环境变量
CLAUDE_CODE_EVEN_MORE_DANGEROUSLY_SKIP_PERMISSIONS=1之后,rm -rf ~这类命令可以不经询问直接执行。 - 文档明确说这层检查会漏判,只针对
rm/rmdir,其他命令同样可能删掉关键路径,所以它不能代替沙箱。
设定:开启 /sandbox,工作目录 ~/workspace/project-A,没有任何 deny 规则。
rm -rf ~/workspace/project-A/build:目标在可写范围内 → 沙箱放行。文档特意提醒:沙箱里的命令照样能删掉你的工作目录。rm -rf ~/.ssh:目标不在可写范围内 → 操作系统拒绝写入,命令失败。
答:第一条在沙箱可写范围内,沙箱放行(要拦得靠权限规则);第二条越出写入边界,就算权限放行,沙箱也会拒绝。
- 以为写了
Bash(rm -rf *)的 deny 规则,就能拦住所有删除。规则按命令文本匹配,rm -fr、find … -delete、写个脚本再执行,都可能不匹配。 - 以为沙箱会"禁止 rm 命令"。沙箱只管路径,不管命令名。
- 防误删最可靠的组合:开沙箱限制写入范围 + 用 git 随时可回滚 + 对重要操作加 ask 规则。
你用 claude --dangerously-skip-permissions 启动,并开了 /sandbox(没开严格模式)。Claude 想执行 curl https://unknown.example.com,这个域名不在白名单里。会发生什么?
想好了,看答案
会直接放行,不会问你。 在 bypassPermissions 模式下,访问白名单外的域名不再询问。另外 Claude 还能不经询问在沙箱外重试命令。想让沙箱真正兜底,需要开 strictAllowlist 和严格沙箱模式(allowUnsandboxedCommands: false)。
Codex 用 --sandbox read-only --ask-for-approval never 运行,它想改一个文件。结果是什么?
想好了,看答案
改不了,而且不会问你。只读沙箱禁止写入,审批策略又是 never,没有人能批准越界,于是这个动作直接失败。
本篇小结
- 沙箱管能不能,审批管问不问,两者各管一层。
- Codex:
read-only/workspace-write(默认不联网)/danger-full-access(没有沙箱)。桌面应用的菜单选项是沙箱和审批打包好的组合,Full access 等于没有沙箱也不询问。 - 底层实现:macOS 用 Seatbelt,Linux 用 bwrap(Codex 还加 seccomp),Windows 上 Codex 用 MXC;Claude Code 在原生 Windows 上没有沙箱。
- Claude Code:
--dangerously-skip-permissions跳过的是询问,/sandbox加的是边界;两者能叠加,但要开严格模式才算真正兜底。 - 拦
rm -rf靠权限规则和危险删除检查,沙箱只管路径。
拓展
以下内容来自 ChatGPT 结合我之前的提问(Pi、ADK、Agent Runtime)做的联想,不属于本篇正文,留作后续学习线索。
为什么 Agent 框架越来越重视沙箱。 普通 LLM 应用的链路是"用户 → 模型 → 文本回答";Agent 则是"用户 → 模型 → 工具调用 → 运行时 → 执行 Shell / Python / 文件操作 → 产生真实的系统副作用"。一旦能调用工具,Agent 就相当于拥有了操作电脑的能力,所以一个完整的 Agent 运行时通常要考虑这几块:
| 组件 | 解决的问题 |
|---|---|
| Agent | 决定做什么 |
| Tool | 提供执行能力 |
| Runtime | 管理工具的执行 |
| Sandbox | 限制执行范围 |
| Approval | 控制敏感操作的授权 |
| Logging | 记录执行过程 |
可以把 Sandbox 看成 Agent Runtime 的"安全执行边界"。这和之前接触的 Pi、ADK、云端 Agent Runtime 的执行架构可以对照着看。
下一步可以学:Sandbox、Docker、VM 有什么区别。 三者都做隔离,但隔离的层次、实现原理和资源开销不同。Claude Code 文档里有一页 Sandbox environments,专门比较内置沙箱、开发容器、容器和虚拟机,可以作为起点。