Skip to content

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.exe program 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 exec blocks 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 | pythonb'', while '' | pythonb'\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.