`never` 不等于放开权限:Codex 里最容易混的三组概念
有两类人会在同一个地方栽跟头。一类看到 Codex(OpenAI Codex)的审批策略里有个 never,理解成「从此它想干啥干啥」,于是死活不敢配;另一类也理解成同一个意思,于是把它当成「一键放开」配上去,然后发现命令还是执行不了,怀疑是 bug。
这两种误解是同一个:把「要不要问你」和「能不能做」当成了一个开关。Codex 里这是两套独立机制,再加上 Windows 平台自己的一层实现,一共有三组概念特别容易糊在一起。下面逐组拆。
先看一行诊断输出,两套机制一目了然
在 codex-cli 0.147.0(Windows 11)上执行 codex doctor --summary,Configuration 分组里那条 sandbox 行本机显示的是:
sandbox restricted fs + restricted network · approval OnRequest
一行里其实塞了三个彼此独立的字段:文件系统边界、网络边界、审批策略。它们各自有各自的取值,谁也不决定谁。如果只有一个开关,这行没必要写成三段。
这行是本篇所有判断的锚点——后面每改一次配置,都回来看它。
第一组:审批策略 vs 沙箱模式
-a, --ask-for-approval 有三档,官方释义是这样的(这里只引和本篇直接相关的三行):
| 取值 | 官方释义 |
|---|---|
untrusted | 只有「受信任」命令(如 ls、cat、sed)免审批;模型提出不在受信集合内的命令时升级给用户 |
on-request | 由模型决定何时请求审批 |
never | 从不询问,执行失败直接回传给模型 |
never 那句话的重点在后半截:执行失败直接回传给模型。也就是说,官方在定义这一档的时候,就已经预设了「命令会失败」这件事仍然存在。如果 never 真的等于放开权限,就不该有「失败」这个分支了。
它改的是失败之后的处理方式——从「弹给你批」变成「把失败结果丢回模型,让模型自己想办法」。沙箱边界一动没动。
真正撤边界的是另外两个东西,两个都在沙箱这一侧:
-s danger-full-access:官方原文是 “The agent runs without sandbox restrictions. This removes the filesystem and network boundaries and should be used only when you want the agent to act with full access.”--dangerously-bypass-approvals-and-sandbox:官方原文是 “EXTREMELY DANGEROUS. Intended solely for running in environments that are externally sandboxed.”
注意第二个的措辞——它说的是「仅用于本身已经被外部沙箱化的环境」,潜台词是你得先有另一层隔离,它才是可考虑的。
怎么自己验一遍边界还在不在:在 codex-cli 0.147.0(Windows 11)上,我们用 codex sandbox 在默认沙箱状态下执行了一条往仓库路径写文件的 cmd /c "echo hi > ...\__sbtest.txt",命令返回之后,那个文件根本不存在(ls 报 No such file or directory)。这就是边界在起作用的样子:命令返回了,但目标路径上并没有出现这个文件。
顺带说个容易踩的:--sandbox-state-disable-network 这类 --sandbox-state-* 选项是一组的,单独给会直接报参数缺失,必须先有 --sandbox-state-json 才能在它之上做增删。
还有一个介于两者之间的选项值得知道:--approve-for-me,官方说明是审批请求走自动复核,并使用 workspace-write 沙箱。配置侧还有一个 approvals_reviewer,默认 user、可设 auto_review。它和 never 的差别在于——never 是「不批了,失败就失败」,auto_review 是「换个东西来批」。想减少弹窗但又不想让判断彻底消失,看的是这个键,不是 never。
第二组:沙箱模式 vs 网络边界
第二个混淆点是把沙箱档位当成了网络开关。
先看 read-only 的官方原文:“The agent can inspect files, but it can’t edit files or run commands without approval.” 这句里的 without approval 常被读漏。它不是「只能看不能动」,而是「要动就得走审批」。
顺着这条读,read-only 配 never 就是个需要想清楚的组合:一边是「要动就得批」,一边是「从不询问、失败直接回传模型」。按官方对这两者的字面释义组合下来,命令大概率是走不通的。这一条我们没有实跑验证过,如果你要这么配,先拿一个无关紧要的目录小范围试一次再铺开。
网络则是完全独立的一维:
workspace-write下是否出网,由sandbox_workspace_write.network_access控制;- 更细的域名级控制走
permissions.<name>.network.domains.<pattern>,取allow/deny,支持通配; - 还有个
features.network_proxy,在 codex-cli 0.147.0 上codex features list里显示它处于 experimental 阶段、当前生效值为false。experimental 的东西别放进你依赖的流程里。 - ChatGPT Work(web)那一侧,官方文档给的做法是去 Settings > Data controls > Work network access,关闭后命令只能访问必需主机名的允许列表。这部分我们没有实测。
所以「我沙箱都设成 workspace-write 了怎么还连不上网」是个典型的两开关当一个用。回到 doctor 那行看 restricted network 还在不在,比猜快得多。
不撤沙箱也能放宽写入范围的做法是 sandbox_workspace_write.writable_roots,CLI 侧还有 --add-dir(主工作区之外额外可写目录)和 -C, --cd(指定 agent 的工作根目录)。需要多一个可写目录,就加目录,别去动沙箱档位——这是本组最实用的一条判断依据。
第三组:Windows 的 elevated/unelevated vs 三档沙箱模式
这一组是中文用户翻车最多的地方,因为两边都叫「模式」,但根本不在一层。-s 的三档说的是「允许 agent 做什么」,windows.sandbox 说的是「这个沙箱在 Windows 上用什么机制实现」。
windows.sandbox | 特征 |
|---|---|
elevated(官方标注为首选) | 使用专用的低权限沙箱用户;文件系统权限边界 + 防火墙规则;需要管理员批准的初始化设置 |
unelevated(回退) | 用「从当前用户派生的受限 Windows token」运行命令;基于 ACL 的文件系统边界;用环境级离线控制替代防火墙规则;保护更弱,但在拿不到管理员批准时可用 |
「保护更弱」是官方自己写的,不是我加的形容词。判断依据很直接:你能不能拿到本机管理员批准。能,就走 elevated;拿不到,unelevated 是有意义的回退,但你要知道自己换来的是什么。另外还有个 windows.sandbox_private_desktop,默认 true。
平台前提也别忽略:Windows 沙箱是在 PowerShell 中原生运行的,不需要 WSL、不需要虚拟机,但要求 winget 可用。版本支持是 Windows 11 推荐、较新的 Windows 10(v1809+)尽力而为(best effort)、更老的 Windows 10 不推荐。
初始化起不来时,官方文档给的排查顺序是四步:① 重启 Codex ② 重试 elevated 初始化 ③ 需要时回退到 unelevated ④ 发送诊断,日志在 CODEX_HOME/.sandbox/sandbox.log。初始化失败的常见原因官方列了三条:拒绝了 UAC 提示、本地用户创建被阻止、防火墙规则被限制。
如果看到错误 1385,官方原文是 “Windows is denying the logon type the sandbox user needs.”,含义是沙箱用户已经建出来了,但策略不允许它执行命令。这条官方只给了上面那四步,网上那些改注册表、改组策略的写法不在官方口径里,我这边也没验证过,不建议照抄。
还有个提示值得留意:如果某个目录是「对所有人可写」的,Codex 会告警,提示 Windows 权限过宽。这是它在告诉你,边界画在这种目录上没什么意义。
最后一句划清界限:macOS 用的是系统内置的 Seatbelt,Linux / WSL2 需要用包管理器装 bubblewrap(bwrap),Windows 是上面这套受限 token 机制。这是三套东西。Linux 上沙箱不生效先查 bwrap 装没装,这条搬到 Windows 上一点用没有,别照着别人的 Linux 帖子在 Windows 上折腾。
从需求倒推:该动哪个开关
把上面三组合并成一份判断清单:
- 想少弹窗 → 动审批策略(
-a never或--approve-for-me),沙箱别碰。 - 想让它能改文件 → 动沙箱档位,
workspace-write本身就是官方标注的默认模式。 - 想多开一个可写目录 → 用
writable_roots或--add-dir,不要为此升到danger-full-access。 - 想断网跑 → 动
network_access,跟审批和文件边界都无关。 - 觉得非
danger-full-access不可 → 先回答一个问题:这台机器本身是不是已经在另一层隔离里?不是的话,先想别的办法。
一段把这些键组合到一起的配置长这样:
sandbox_mode = "workspace-write"
approval_policy = "never"
[sandbox_workspace_write]
network_access = false
writable_roots = ["<你的额外可写目录>"]
[windows]
sandbox = "elevated"
sandbox_private_desktop = true
以上为按官方文档键位组合的示例,未逐项实测,以官方文档为准。
临时试的话不必改文件,用 -c 顶层选项覆盖即可,点号路径表示嵌套:
codex -c sandbox_workspace_write.network_access=false doctor --summary
-c 的 value 按 TOML 解析,解析失败会按字面字符串处理——这一点很坑,因为它不会当场喊错。
改完之后怎么确认真的生效了
先跑 codex doctor --summary,看两行:sandbox 行的三个字段是不是你要的,以及 Configuration 里的 config 行。
在 codex-cli 0.147.0(Windows 11)上,我们故意传了一段语法不合法的 TOML(codex -c 'features=[unclosed' doctor --summary),结果是 doctor 没有崩溃退出,照常跑完了,但报告里出现了:
✗ config config could not be loaded - Fix the reported config error, then rerun codex doctor.
这个行为很有用:配置坏掉的时候,Codex 不会拦住你,它会带着「配置没加载成功」继续跑。所以「我明明改了配置怎么没生效」的第一步永远是跑 doctor 看这一行,而不是反复改配置。
有个叫 --strict-config 的选项,作用是配置里出现本版本不认识的字段时直接报错退出。但它有边界:在 codex-cli 0.147.0(Windows 11)上执行 codex -c model_reasoning_effortt=high --strict-config exec --help,help 正常打印,没有报未知字段错误。说明校验发生在真正加载配置去跑会话的时候,--help 这种不进入会话的路径不触发。别把它当成「任何情况下都能拦住拼写错误」的保险。
还有一条顺手的:取值写错时报错是很明确的。在 codex-cli 0.147.0(Windows 11)上执行 codex -s bogus-mode 得到:
error: invalid value 'bogus-mode' for '--sandbox <SANDBOX_MODE>'
[possible values: read-only, workspace-write, danger-full-access]
枚举值一共就这三个,记不住的时候故意写错一次比翻文档快。
回到开头那句话:never 管的是嘴(问不问你),沙箱管的是手(能不能做),Windows 的 elevated/unelevated 管的是手是怎么被绑住的。三个位置分开看,大部分「配了没用」和「配了不敢用」都能自己判掉。
相关阅读
- Codex 审批策略拆解:三档字符串与五个细粒度开关怎么选
- Codex 自定义权限档:按目录和域名给 AI 发通行证
- 从权限模型看 Codex 与其它编程 agent 的差别:选型前该问清楚的五个维度
- Codex 的六个使用面:一张图看懂该用哪个
本文依据 Codex 官方文档(learn.chatgpt.com/docs/ 的《Sandbox》《Windows sandbox》《Permissions》页面)整理,核对日 2026-08-09;文中标注「本机实测」的部分基于 codex-cli 0.147.0 / Windows 11 环境下的只读命令输出。产品功能、模型与价格以官方最新说明为准。桌面应用与云端部分为官方文档口径,非本机实测。