source · ingested Jul 12, 2026 · updated Jul 18, 2026

为 Windows 上的 Codex 构建安全高效的沙箱环境

David Wiesen published May 13, 2026 #codex#sandboxing#windows#agent-security#openai
Original article: openai.com/zh-Hans-CN/index/building-codex-windows-sandbox · Ingested copy: raw/2026-07-12-codex-windows-sandbox-engineering.md

An openai engineering post by David Wiesen (Member of Technical Staff, Codex engineering team since September 2025) narrating the full design history of the codex sandbox on Windows — from “no sandbox at all” through a rejected survey of native Windows primitives, a first unelevated prototype, to the shipped elevated design with dedicated sandbox users and firewall rules. The through-line: Windows offers no single OS primitive that maps to “safe autonomous coding agent” (agent-sandboxing), so the team composed SIDs, write-restricted tokens, local users, DPAPI-encrypted credentials, and Windows Firewall rules into a four-binary architecture. The wiki’s most detailed account of what the execution boundary layer of a harness costs to actually build.

Source file: raw/2026-07-12-codex-windows-sandbox-engineering.md (Chinese translation of the English original; quotes below keep the Chinese with English glosses). Seven architecture diagrams are rehosted and part of the evidence — notably the write-check table (both the regular user and the sandbox-write SID must pass), the failed-vs-working command-runner flow comparison, and the final-architecture diagram showing named-pipe IPC and the sandbox control plane (~/.codex/.sandbox, ~/.codex/.sandbox-secrets, ~/.codex/cap_sid — visible only in the diagram, not the prose).

Summary

The problem

Codex runs on developer laptops (CLI, IDE extension, desktop app) with the real user’s permissions. Its default mode promises: read almost anywhere, write only inside the workspace, no network unless approved. Enforcing that promise requires OS-level isolation — Seatbelt on macOS, seccomp/bubblewrap on Linux — but Windows ships nothing equivalent, so Windows users were stuck choosing between approving nearly every command (including reads) or Full Access mode with no oversight.

Rejected: the native Windows options

OptionWhy it looked rightWhy it was rejected
AppContainerReal OS boundary, capability-basedBuilt for apps that declare their needs up front; Codex drives open-ended dev workflows (shells, Git, Python, build tools, arbitrary binaries)
Windows SandboxDisposable lightweight VM, strongest isolationCodex must act on the user’s actual checkout/tools/env, not a throwaway desktop; not available on Windows Home SKUs
MIC integrity labelsNon-admin path with real OS enforcementRelabeling a workspace low-integrity means any low-integrity process can write there — turns the user’s checkout into a host-wide low-integrity sink

Prototype 1: the “unelevated sandbox”

Goal: no admin prompts ever. Two mechanisms:

  • File writes — enforced. Setup creates a synthetic SID (sandbox-write), grants it write/execute/delete ACLs on the workspace and configured writable_roots, explicitly denies it on carve-outs (<cwd>/.git, <cwd>/.codex, <cwd>/.agents), then launches commands under a write-restricted token whose restricted SID list is [Everyone, logon-session SID, sandbox-write]. A write succeeds only if both the regular user and at least one restricted SID are allowed — so the ACLs define exactly where the sandbox can modify the filesystem.
  • Network — advisory only. Windows Firewall needs admin, so the prototype “poisons the obvious escape hatches”: proxy env vars pointed at a dead endpoint (HTTPS_PROXY=http://127.0.0.1:9, ALL_PROXY, GIT_HTTPS_PROXY), GIT_SSH_COMMAND=cmd /c exit 1, plus a denybin directory prepended to PATH with stub SSH/SCP scripts and a reordered PATHEXT.

Tradeoffs: setup ACLs can be slow on large workspace topologies; real ACLs leave a (mild) footprint on the host; ACL-based semantics are expensive to change (vs. regenerating a .sbpl file on macOS). All tolerable — except the network story: any process that ignores env vars or opens sockets directly walks straight through. That one flaw killed the design.

Prototype 2: the shipped “elevated sandbox”

To make firewall rules stick, sandboxed commands must run as a separate principal. Windows can’t match a firewall rule to “any token whose restricted SID list contains our synthetic SID”, nor per-invocation program rules — so Codex creates two local users at setup:

  • CodexSandboxOffline — targeted by a block-all-outbound firewall rule
  • CodexSandboxOnline — not targeted (for runs where network is approved)

The restricted token machinery stays the same (write_restricted, [Everyone, Logon, Synthetic]), but the token’s principal is now a sandbox user instead of the real user. Consequences cascade:

  • First-class elevated setup step (dedicated binary, codex-windows-sandbox-setup.exe): create the SID; create both users; store their credentials DPAPI-encrypted where the sandbox users can’t read them; create/validate the firewall rule. Because sandbox users can’t read other users’ profiles by default, setup also grants best-effort read ACLs on common roots (C:\Users\<real-user>, C:\Windows, C:\Program Files, C:\Program Files (x86), C:\ProgramData) — run asynchronously since per-directory ACL installation is expensive.
  • A command-runner binary (codex-command-runner.exe): the intended single-process flow (real user → LogonUserWCreateRestrictedTokenCreateProcessAsUserW) fails at a privilege wall — codex.exe can mint the restricted token but can’t reliably spawn with it from the real-user side. So the flow is split: codex.exe calls CreateProcessWithLogonW to launch the runner as the sandbox user (no restricted token yet); inside the runner, OpenProcessToken + GetTokenInformation extract the sandbox logon SID, CreateRestrictedToken builds the final token, and CreateProcessAsUserW spawns the real child — all on the sandbox-user side of the boundary. Parent and runner speak length-prefixed JSON frames over a named pipe (spawn_request / spawn_ready / output — per the final architecture diagram).

Final architecture, four layers: codex.execodex-windows-sandbox-setup.exe (elevated setup) → codex-command-runner.exe (token minting + spawn) → child processes.

Key claims

  • Every Codex command is sandboxed from the start, and every descendant process inherits the same boundary — restrictions propagate down the process tree. (agent-sandboxing)
  • Codex’s default mode: read almost anywhere, write only in the workspace, no network unless explicitly enabled — and it needs a sandbox that actually enforces this, not policy text. (agent-sandboxing, harness)
  • macOS and Linux get OS primitives (Seatbelt; seccomp/bubblewrap); Windows has no out-of-the-box equivalent, so OpenAI implemented its own. (agent-sandboxing)
  • On macOS the sandbox semantics live in a dynamically generated .sbpl Seatbelt profile — cheap to change; the Windows ACL approach makes semantic changes slow and heavyweight. (agent-sandboxing)
  • Env-var network suppression is advisory: it catches proxy-honoring tools but “在设计之初就无法抵御恶意对抗代码” (was never designed to hold up against adversarial code) — and even well-intentioned binaries bypass it by shipping their own socket code. This alone justified the elevated redesign. (prompt-injection)
  • Windows Firewall cannot target a restricted token’s non-principal identity, and program-path rules can’t distinguish this sandboxed python.exe from any other — hence the dedicated-user design.
  • Write carve-outs inside writable roots (.git, .codex, .agents) are explicitly denied — the agent can edit your code but not your Git metadata or its own config/instructions. (agent-sandboxing)
  • Sandbox-user credentials are stored DPAPI-encrypted where the sandbox users themselves cannot read them — the sandbox must not be able to unlock itself.
  • Setup logic lives in its own binary to cross the UAC boundary only when needed, keep codex.exe an unelevated harness on all platforms, and decouple long-running setup from the main process lifetime.
  • Lesson 1: “Windows 并没有直接为我们提供一个能够完美对应’安全自主编程智能体’的原语” (Windows did not hand us one primitive that cleanly maps to “safe autonomous coding agent”) — the shipped design is a hybrid of prototypes that each solved part of the problem.
  • Lesson 2: coding-agent security is a different beast from classic application security — the workload is open-ended developer workflows, and the engineering is balancing compatibility with agentic workloads against real enforcement. (agent-sandboxing, harness)

Notable quotes

每一个 Codex 命令从一开始就处于沙箱之中,且其所有子进程 (descendant process) 也都保持在相同的边界内。 (Every Codex command is sandboxed from the start, and every descendant process stays inside the same boundary.)

这种做法虽然拦截了大量由常规工具驱动的流量,但它仍然只是建议性的。任何进程都可以忽略环境变量、绕过 PATH,或者直接建立套接字 (socket) 进行连接 — 这带来很大风险。 (That caught a lot of normal tool-driven traffic, but it was still only advisory. A process could ignore the environment, bypass PATH, or just open sockets directly — too risky.)

我们并不想阻止 443 端口,而是想阻止这个特定受限进程树的任意出站访问。 (We didn’t want to block port 443; we wanted to block arbitrary outbound access for this specific restricted process tree.)

编程智能体的安全问题与更传统的应用程序安全有着本质的不同。Codex 必须适用于真实的开发者工作流。我们的工程重心,始终是在兼容智能体工作负载与保障真实强制力之间找到平衡。 (Security for a coding agent is a different beast than more classic application security. Codex has to work for real developer workflows. The engineering work was about balancing compatibility with agentic workloads against real enforcement.)

Open questions

  • Read access is best-effort by design. The elevated sandbox grants read ACLs asynchronously to a hand-picked directory list; reads outside that list (custom tool installs, other drives) presumably fail until approved or ACL’d. How often this bites in practice — and what the approval UX looks like — isn’t covered.
  • The sandbox control plane is diagram-only. ~/.codex/.sandbox, ~/.codex/.sandbox-secrets, ~/.codex/cap_sid and the named-pipe JSON protocol appear in the final architecture diagram but are never explained in prose. The IPC attack surface (can a sandboxed child talk to the pipe?) is unaddressed.
  • CodexSandboxOnline scoping. When network is approved, the online user has no firewall rule at all — is egress scoped (allowlisted domains?) or fully open? The post doesn’t say.
  • Cross-agent comparison. How claude-code handles the same Windows gap (no Seatbelt/seccomp equivalent) is not in the wiki yet — worth a source if Anthropic publishes one.
  • Threat-model boundary. The post frames the sandbox against accidental damage and data exfiltration, but doesn’t state whether it’s claimed to hold against a deliberately adversarial model (vs. adversarial code the model runs). The unelevated design explicitly wasn’t; the elevated design’s claim strength is left implicit.

Pointers

  • agent-sandboxing — the concept page distilled from this source: sandbox as the enforced execution boundary for coding agents; per-OS primitives; the design axes this post surfaces (enforcement strength, elevation cost, semantics changeability, setup latency).
  • codex — this is the wiki’s first source about the shipped external Codex product surface (CLI / IDE extension / desktop app), complementing 2026-04-27-harness-engineering-codex-agent-first (the team’s internal development environment) and 2026-04-27-codex-context-compaction-investigation (server-side API internals).
  • harness — the execution boundary row of the four-part harness table, instantiated at OS level; this post is the wiki’s best evidence of how much engineering that row costs when the OS doesn’t cooperate.
  • prompt-injection — network suppression is the enforcement-level backstop for the exfiltration sink: even a successfully injected agent can’t upload data if the process tree has no outbound network.

Referenced by 6

harness-why-it-matters-now agent-sandboxing harness prompt-injection codex openai
esc