Codex Windows sandbox — broken, and how to work around it¶
Status: broken on this fleet. Confirmed 2026-07-16, Codex v0.144.1.
Every codex exec / codex review that shells out MUST pass
-c sandbox_mode="danger-full-access".
What the override trades away: it runs Codex with no sandbox — full user rights to execute anything, not merely read a diff. Acceptable only on this trusted home fleet reviewing our own code. Never carry the flag onto a shared box, a CI runner, or any repo whose contents you don't control — a hostile diff would get arbitrary execution. The honest status is "sandbox broken, isolation deliberately disabled," not "fixed."
The failure¶
With the sandbox on (the default, sandbox_mode = "workspace-write" in ~/.codex/config.toml),
every command Codex tries to run dies instantly:
ERROR codex_core::exec: exec error: windows sandbox: CreateProcessWithLogonW failed: 2
Why this is worse than a crash¶
codex review --uncommitted still exits 0 and reports "no findings" while every git
command underneath fails. It does not error out — it returns a confident clean review of a
diff it never saw. A silently blind gate is more dangerous than a broken one, because it
looks like a pass. Any harness that trusts a Codex verdict without the override is trusting
nothing.
Root cause (confirmed, not theorized)¶
The sandbox launches the shell under a separate logon via CreateProcessWithLogonW.
pwsh on these boxes is a per-user app-execution alias:
C:\Users\<user>\AppData\Local\Microsoft\WindowsApps\pwsh.exe
-> C:\Program Files\WindowsApps\Microsoft.PowerShell_7.6.3.0_x64__8wekyb3d8bbwe\pwsh.exe
WindowsApps is ACL-locked per-user, so the sandbox's logon token cannot reach that binary
→ ERROR_FILE_NOT_FOUND (2).
Negative control that confirms it (WT-e7d7, independently reproduced): with
-c sandbox_mode="danger-full-access", Codex exec'd the exact same alias path and it
succeeded in 4541ms with real findings returned. Same binary, same path — sandbox off works,
sandbox on fails. The blocker is the logon token, not the path and not a missing file.
What this is NOT¶
- NOT a missing helper. The older
orchestrator_helper_launch_failed/ "codex-windows-sandbox-setup.exeprogram not found" failure (v0.142.5–0.144.1, diagnosed 2026-07-08) is fixed — the helper now ships in the CLI bin (...\AppData\Local\Programs\OpenAI\Codex\bin\, dated 2026-07-13). Different bug, same symptom class. Docs still blaming the helper are stale. - NOT fixable by reinstalling Codex. The negative control rules it out.
Candidate real fix (unverified — needs elevation, ask Andrew)¶
Install non-Store PowerShell 7 via MSI to C:\Program Files\PowerShell\7\pwsh.exe (no such
install exists on this box today) so the sandbox logon can reach a real shell binary outside
WindowsApps. May still be insufficient: the sandbox likely also needs a local user account
that CreateProcessWithLogonW can authenticate against.
Other gotchas when scripting Codex¶
codex execblocks on stdin. It prints "Reading additional input from stdin..." and hangs forever with no output. One test hung 7 minutes before this was spotted. Any scripted/detached call must close stdin, using the form that matches the shell:- PowerShell:
$null | codex exec -c sandbox_mode="danger-full-access" "..." - Bash:
codex exec -c sandbox_mode="danger-full-access" "..." < /dev/null
PowerShell has no < redirection — it errors with The '<' operator is reserved for
future use., so neither < /dev/null nor < $null works there. $null | closes the
handle and the child reads clean EOF (verified: $null | python → b'', while
'' | python → b'\r\n').
Related trap: don't route through cmd just to get < NUL. < NUL is harmless in
itself, but cmd.exe caps the command line at ~8k and silently truncates a real
diff — that's what kills the Gemini seat.
- codex review --uncommitted and a custom prompt are mutually exclusive. Use the
default review output as-is.
- Ignore rmcp::transport::worker ... http://10.0.0.26:37878/mcp errors. The
streaming-PC council host is up — it answers HTTP 401. Codex just isn't sending the
Bearer token. It's a Codex-side MCP auth/config bug, not a dead host — do not restart the
streaming PC.