OpenAI 给 Codex 在 Windows 造了一个沙箱,过程比想象中曲折 · AI HOT
meng shao @shao__meng 50
2026-05-14 13:09 ·49天前
AI 摘要 OpenAI 为在 Windows 上实现 Codex 的“默认安全”体验,从免提权沙箱演进到提权沙箱。Windows 缺乏原生进程级约束,初期方案通过合成 SID 和 Write-Restricted Token 限制文件写入,但网络封锁只能依赖环境变量软拦截,无法强制生效。团队最终放弃免提权约束,转向创建独立本地用户(在线与离线沙箱用户),需一次性管理员权限安装并配置防火墙规则。通过引入 codex-command-runner.exe 作为中介,解决跨用户创建受限令牌进程的权限难题,形成四层架构,在保障安全的同时最小化对主流程的侵入。
meng shao @shao__meng · X 2026-05-14 13:09 · 49天前
在 X 看原推 · x.com AI 摘要 OpenAI 为在 Windows 上实现 Codex 的“默认安全”体验,从免提权沙箱演进到提权沙箱。Windows 缺乏原生进程级约束,初期方案通过合成 SID 和 Write-Restricted Token 限制文件写入,但网络封锁只能依赖环境变量软拦截,无法强制生效。团队最终放弃免提权约束,转向创建独立本地用户(在线与离线沙箱用户),需一次性管理员权限安装并配置防火墙规则。通过引入 codex-command-runner.exe 作为中介,解决跨用户创建受限令牌进程的权限难题,形成四层架构,在保障安全的同时最小化对主流程的侵入。
最终方案:「提权沙箱」(Elevated Sandbox)
1. 引入两个本地用户 Codex 在安装时创建: · CodexSandboxOffline -- 防火墙规则全封; · CodexSandboxOnline -- 不被防火墙规则覆盖。 子进程依旧跑在带 【Everyone, Logon, Synthetic】 受限 SID 列表的 write-restricted token 下,但 token 的主体(principal)换成了沙箱用户,而不是真实用户。
5.2 一次性 setup 步骤(需要管理员) · 创建合成 SID; · 创建在线 / 离线沙箱用户; · 凭据用 DPAPI 加密存储,沙箱用户自己读不到; · 为 CodexSandboxOffline 创建"封禁所有出站"的防火墙规则; · 给沙箱用户补 读 ACL--因为新用户默认读不到其他用户的 profile、C:\Users、C:\Program Files 等常用目录。这一步耗时,异步执行,不阻塞用户。
5.3 为什么需要 codex-command-runner.exe 直觉的流程是: codex.exe → LogonUserW → CreateRestrictedToken → CreateProcessAsUserW(child) 但在 CreateProcessAsUserW 这一步存在特权墙:以"真实用户"身份是无法可靠地把进程以另一个用户的受限 token 拉起来的。
解法是把流程切成两段: Part 1(在真实用户侧) · codex.exe 用 CreateProcessWithLogonW 把 codex-command-runner.exe 以沙箱用户身份拉起(此时还不是受限 token)。 Part 2(已经在沙箱用户侧) · runner 用 OpenProcessToken 拿到自己的 token; · GetTokenInformation 取出 logon SID; · CreateRestrictedToken 构造最终受限 token; · CreateProcessAsUserW 拉起真正的子进程。
5.4 最终四层架构 · codex.exe -- 普通非提权的 harness; · codex-windows-sandbox-setup.exe -- 一次性的提权安装; · codex-command-runner.exe -- 在沙箱用户内造受限 token 并起子进程; · child process -- 真正受约束的命令。
拆成独立二进制的好处:codex.exe 在其他平台不被 Windows 专属逻辑污染;UAC 边界只在必要时跨越;setup 的长耗时与主进程生命周期解耦。
Tibo We are continuing to invest in making agents work better on Windows. Highly recommend reading David's engineering post on our unique approach to windows sandbox...
现成 Windows 方案为什么都不够用? · AppContainer:是为"功能边界清晰的应用"设计的;Codex 要驱动 shell、Git、Python、构建工具等任意二进制,形状不对 · Windows Sandbox:它是隔离的"另一个桌面",无法直接作用于用户的真实仓库;且 Windows Home 版根本没有 · Mandatory Integrity Control:把工作区标成 Low,等于让所有 Low 进程都能写入,宿主信任模型被破坏,副作用太大
第一版原型:「免提权沙箱」(Unelevated Sandbox) 设计原则:不弹 UAC、不要求管理员。需要解决两件事:限制文件写入 + 限制网络。
1. 文件写入:靠 SID + Write-Restricted Token 真正落地 · 合成 SID:Windows 允许创建一个不绑定真实用户、却能出现在 ACL 中的身份。Codex 为此造了一个专属的 sandbox-write SID。 · Write-Restricted Token:一种特殊进程令牌,写操作要双重放行--token 的真实用户身份有权限; token 的"受限 SID 列表"中至少一个 SID 也被授权。
把 sandbox-write SID 通过 ACL 授予: · 当前工作目录 · config.toml 里配置的 writable_roots
并显式拒绝其写入 .git / .codex / .agents。 → 这是真正的 OS 级写边界。
2. 网络访问:只能"劝退",无法强制 Windows Firewall 必须管理员权限,于是只能做环境层面的软封锁: HTTPS_PROXY / ALL_PROXY / GIT_HTTPS_PROXY = http://127.0.0.1:9 GIT_SSH_COMMAND = cmd /c exit 1 外加在 PATH 前塞 denybin,让假的 ssh/scp 先被解析到。
效果:拦得住行为良好的工具;但凡自己实现网络栈、绕过 PATH、或直接开 socket 的程序--一律失效。仅是 advisory,挡不住对抗性代码。
改版关键:为什么必须接受"需要提权" 要让 Windows Firewall 真正生效,必须按"身份"匹配规则。但: · 防火墙规则不能匹配 restricted token 中的合成 SID; · 按 codex.exe 路径匹配,覆盖不到它派生的 Git/Python 等子进程; · 按用户匹配又会误伤真实用户本人; · 按端口/地址匹配是错的策略--目标不是封 443,而是封这一棵受限进程树的所有出站流量。
唯一的出路:让沙箱命令以"另一个 Windows 用户"的身份运行。这就必须放弃"免提权"约束。
最终方案:「提权沙箱」(Elevated Sandbox)
1. 引入两个本地用户 Codex 在安装时创建: · CodexSandboxOffline -- 防火墙规则全封; · CodexSandboxOnline -- 不被防火墙规则覆盖。 子进程依旧跑在带 【Everyone, Logon, Synthetic】 受限 SID 列表的 write-restricted token 下,但 token 的主体(principal)换成了沙箱用户,而不是真实用户。
5.2 一次性 setup 步骤(需要管理员) · 创建合成 SID; · 创建在线 / 离线沙箱用户; · 凭据用 DPAPI 加密存储,沙箱用户自己读不到; · 为 CodexSandboxOffline 创建"封禁所有出站"的防火墙规则; · 给沙箱用户补 读 ACL--因为新用户默认读不到其他用户的 profile、C:\Users、C:\Program Files 等常用目录。这一步耗时,异步执行,不阻塞用户。
5.3 为什么需要 codex-command-runner.exe 直觉的流程是: codex.exe → LogonUserW → CreateRestrictedToken → CreateProcessAsUserW(child) 但在 CreateProcessAsUserW 这一步存在特权墙:以"真实用户"身份是无法可靠地把进程以另一个用户的受限 token 拉起来的。
解法是把流程切成两段: Part 1(在真实用户侧) · codex.exe 用 CreateProcessWithLogonW 把 codex-command-runner.exe 以沙箱用户身份拉起(此时还不是受限 token)。 Part 2(已经在沙箱用户侧) · runner 用 OpenProcessToken 拿到自己的 token; · GetTokenInformation 取出 logon SID; · CreateRestrictedToken 构造最终受限 token; · CreateProcessAsUserW 拉起真正的子进程。
5.4 最终四层架构 · codex.exe -- 普通非提权的 harness; · codex-windows-sandbox-setup.exe -- 一次性的提权安装; · codex-command-runner.exe -- 在沙箱用户内造受限 token 并起子进程; · child process -- 真正受约束的命令。
拆成独立二进制的好处:codex.exe 在其他平台不被 Windows 专属逻辑污染;UAC 边界只在必要时跨越;setup 的长耗时与主进程生命周期解耦。
Tibo We are continuing to invest in making agents work better on Windows. Highly recommend reading David's engineering post on our unique approach to windows sandbox...