Confirmed root cause on Codex 0.147.0: missing inherited Window Station/Desktop access in a Windows OpenSSH Session 0

Open 💬 2 comments Opened Aug 9, 2026 by TheLearnerL

Confirmed root cause on Codex 0.147.0: missing inherited Window Station/Desktop access in a Windows OpenSSH Session 0

I can reproduce the failure deterministically on Codex CLI 0.147.0 and have completed an A-B-A causal test.

The evidence indicates that the elevated sandbox bootstrap runner is launched with CreateProcessWithLogonW from a non-interactive OpenSSH Session 0, but the selected sandbox account is not granted access to the inherited service Window Station and Desktop.

This causes codex-command-runner-0.147.0.exe to fail during process initialization with 0xC0000142. Codex then waits 15 seconds for the runner pipe and reports a timeout.

All machine-specific names, full SIDs, usernames, and workspace paths below have been redacted.

Environment

  • Codex CLI: official standalone stable 0.147.0
  • Windows: Windows 11 x64, build 26200 (10.0.26200.8457)
  • Remote transport: Windows OpenSSH
  • Client: Codex desktop application launching the remote Codex app-server through SSH
  • Host process session: Session 0
  • Sandbox configuration:
  • windows.sandbox = "elevated"
  • windows.sandbox_private_desktop = true
  • Sandbox provisioning command completed successfully from an elevated PowerShell:
  • codex sandbox setup --elevated --current-user
  • exit code 0
  • The same official Codex binary and sandbox configuration work from an interactive Session 1.

Original failure

The native elevated sandbox consistently fails over the SSH Session 0 path with:

windows sandbox failed: timed out after 15000ms connecting runner pipe-in

A representative reproduction command is:

$codex = "$env:USERPROFILE\.codex\packages\standalone\current\bin\codex.exe"

& $codex sandbox `
  -P :workspace `
  -c windows.sandbox=elevated `
  -c windows.sandbox_private_desktop=true `
  -C $PWD `
  "$env:SystemRoot\System32\cmd.exe" `
  /d /c "echo SESSION0_BASELINE_OK"

Baseline result:

BASELINE_EXIT=1
windows sandbox failed: timed out after 15000ms connecting runner pipe-in

The timeout is a downstream symptom. Windows records the earlier bootstrap failure in the System event log:

Application Popup
Event ID: 26
Process: codex-command-runner-0.147.0.exe
The application was unable to start correctly (0xc0000142).

0xC0000142 is the process/DLL initialization failure status.

Event timeline

The relevant events occurred in this order:

01:59:24.357  Elevated sandbox launch started
01:59:24.489  Sandbox setup/account refresh started
01:59:24.532  Setup completed, errors=[]
01:59:24.546  Filesystem ACL inspection/refresh started
01:59:24.553  Filesystem ACL step completed
01:59:24.562  command-runner helper cache/path resolved
01:59:24.566  Security event 4624: sandbox account successfully logged on
01:59:24.609  System event 26: command runner failed with 0xC0000142
01:59:39.575  Sandbox logon session ended after the 15-second pipe wait

The active sandbox log was the dated file:

%USERPROFILE%\.codex\.sandbox\sandbox.2026-08-09.log

This shows that provisioning, account lookup, credential logon, filesystem ACL handling, and runner path resolution all completed before the runner initialization failure.

Session 0 Window Station/Desktop state

The SSH-hosted Codex process was running on:

Session ID: 0
Window Station: Service-0x0-<LUID>$
Desktop: Default

Before the causal test, the Window Station and Desktop DACLs contained access entries for:

<interactive-user>
BUILTIN\Administrators

They contained no access entry for either native Codex sandbox account:

CodexSandboxOffline
CodexSandboxOnline

Both sandbox accounts existed and were enabled.

Their direct local group membership was limited to:

CodexSandboxUsers
BUILTIN\Users

The CodexSandboxUsers group contained exactly the two native sandbox accounts.

Account and logon-policy checks

The sandbox accounts effectively received:

SeInteractiveLogonRight
SeNetworkLogonRight

No applicable deny-logon right applied to either account.

The Windows Security log recorded:

Event 4648: explicit credentials used
Event 4624: successful logon
Logon Type: 2
Account: CodexSandboxOffline

There was no corresponding event 4625 authentication failure.

Therefore, this was not caused by an invalid password, a disabled account, missing interactive logon rights, or an explicit deny-logon policy.

A-B-A causal test

I performed a reversible A-B-A experiment against the exact same SSH Session 0 and the exact same official Codex 0.147.0 binary.

A1 — Original DACL

No sandbox-account ACE was present on the current Session 0 Window Station or Desktop.

Result:

BASELINE_EXIT=1
windows sandbox failed: timed out after 15000ms connecting runner pipe-in
B — Add only the missing sandbox-account access

I temporarily added an ACE for the CodexSandboxOffline account SID to the current inherited objects.

No group, user, service, Codex configuration, executable, or filesystem permission was changed.

The masks used were the standard non-interactive Window Station/Desktop masks:

Window Station: 0x000F006E
Desktop:        0x000F00CF

The exact same official sandbox command was then run with a different output marker.

Result:

PROBE_EXIT=0
SESSION0_DACL_CAUSAL_OK

There was:

no runner pipe timeout
no 0xC0000142 event for this launch
no stderr output

The native elevated sandbox therefore completed successfully inside the same SSH Session 0 after only the missing object access was supplied.

Restore

The original binary security descriptors were restored in a finally path.

Before/after SHA-256 checks were identical:

Window Station:
C22FE903AFC19D63F06DB090379CD5C98816F5CC45DCD86A530471BED2BF9365

Desktop:
F78C04E3B3BFC5F6322100CE288EB5678BC45E5576261724843C38E8A33446E1

Verification:

STATION_RESTORED_EXACT=True
DESKTOP_RESTORED_EXACT=True
A2 — Original DACL restored

After exact restoration, the same official command was executed again.

Result:

POST_RESTORE_EXIT=1
windows sandbox failed: timed out after 15000ms connecting runner pipe-in

The observed sequence was therefore:

missing ACE -> failure
temporary minimal ACE -> success
exact DACL restoration -> same failure returns

This demonstrates direct causality rather than correlation.

Interactive Session 1 control test

The same official Codex 0.147.0 executable, sandbox accounts, configuration, and machine succeeded when launched from an interactive Session 1:

SESSION1_NATIVE_OK
exit code 0

The firmware, virtualization state, installed Windows components, sandbox accounts, and Codex files were unchanged. The material difference was the inherited Windows session and GUI-object security context.

Source-code match

In Codex 0.147.0, the elevated runner bootstrap code creates a zeroed STARTUPINFOW, sets only cb, leaves lpDesktop null, and calls CreateProcessWithLogonW directly:

https://github.com/openai/codex/blob/rust-v0.147.0/codex-rs/windows-sandbox-rs/src/elevated/runner_client.rs#L291-L343

The corresponding current main implementation still follows the same launch sequence:

https://github.com/openai/codex/blob/main/codex-rs/windows-sandbox-rs/src/elevated/runner_client.rs

The private desktop is created later by the already-running command runner:

https://github.com/openai/codex/blob/rust-v0.147.0/codex-rs/windows-sandbox-rs/src/bin/command_runner/win.rs#L221-L337

https://github.com/openai/codex/blob/rust-v0.147.0/codex-rs/windows-sandbox-rs/src/desktop.rs#L56-L176

Therefore, changing windows.sandbox_private_desktop cannot fix this bootstrap failure. The runner must start successfully before it can create or use the final private desktop.

Windows API contract

Microsoft documents the relevant responsibility for CreateProcessWithLogonW:

By default, CreateProcessWithLogonW creates the new process on a noninteractive window station with a desktop that is not visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default interactive window station and desktop, winsta0\default, in the lpDesktop member of the STARTUPINFO structure. In addition, before calling CreateProcessWithLogonW, the application must add permission for the specified user account to the specified window station and desktop.

API documentation:

https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithlogonw

Microsoft also documents the dynamically created non-interactive service Window Station naming and default access model:

https://learn.microsoft.com/en-us/windows/win32/winstation/window-station-and-desktop-creation

Process-to-Window-Station association is documented here:

https://learn.microsoft.com/en-us/windows/win32/winstation/process-connection-to-a-window-station

In this case, lpDesktop is null, so the runner inherits the caller's Session 0 service Window Station/Desktop context. The selected sandbox account has not been granted access to those inherited GUI objects.

Other causes ruled out

The following were checked and did not explain the failure:

  • Sandbox provisioning failure
  • Missing or disabled sandbox accounts
  • Incorrect sandbox account password
  • Missing interactive logon right
  • An applicable deny-logon policy
  • Runner executable missing from cache
  • Filesystem read/traverse ACL failure
  • AppLocker
  • effective policy contained no rule collections
  • no AppLocker event matched Codex
  • WDAC/Code Integrity
  • no Code Integrity event matched codex.exe, codex-command-runner, or .codex
  • Firmware virtualization
  • Hyper-V
  • Windows Sandbox optional component
  • WSL/WSL2
  • The final Codex private desktop option

Firmware virtualization, Hyper-V, Windows Sandbox, and WSL2 are separate virtualization features. The failing native Codex path had already reached CreateProcessWithLogonW and the Windows GUI-object access boundary.

Why reboot appeared to change the behavior

The Service-0x...$ Window Station is a dynamic object associated with the non-interactive service logon session.

A temporary ACE applied directly to one instance is not a persistent Codex configuration. After reboot or service/session recreation, Windows creates a new service-session Window Station/Desktop using its normal DACL construction.

This explains why a previous temporary repair could work before reboot and disappear afterward.

Suggested upstream fix

The durable fix appears to belong in:

codex-rs/windows-sandbox-rs/src/elevated/runner_client.rs

Before calling CreateProcessWithLogonW, the runner launcher should:

  1. Resolve the account SID for the selected sandbox_creds account, either Offline or Online.
  2. Open the current inherited Window Station and Desktop.
  3. Add only the minimal required ACEs for that sandbox account.
  4. Keep those ACEs valid until the runner has connected its pipe and completed the bootstrap/SpawnReady phase.
  5. Remove only the ACEs inserted by that launch.
  6. Handle concurrent Offline/Online launches with serialization or reference counting so one launch cannot remove another launch's ACE.
  7. Avoid replacing or restoring the entire DACL in a way that could overwrite unrelated concurrent ACL changes.

The final private desktop should remain enabled by default. These are two separate security layers:

Layer 1: bootstrap runner access to the inherited Session 0 objects
Layer 2: final sandbox command isolation on Codex's private desktop

Fixing Layer 1 should not weaken Layer 2.

Current machine state after testing

The diagnostic ACEs were removed and both original binary security descriptors were restored exactly.

No persistent workaround remains:

no scheduled task
no helper service
no sshd DefaultShell wrapper
no login script
no sandbox-account group change
no Codex executable modification
no persistent Window Station/Desktop ACE

As expected after restoration, the official native elevated sandbox still fails over the SSH Session 0 path and still succeeds in interactive Session 1.

This evidence strongly suggests that issue #27265 is a reproducible caller-side bootstrap ACL defect rather than an unsupported Windows configuration, virtualization problem, or machine-specific policy failure.

View original on GitHub ↗

2 Comments

jdcodes1 · 9 days ago

Your diagnosis matches the code. In spawn_runner_transport the elevated runner is launched with a zeroed STARTUPINFOWlpDesktop is never set — and nothing grants the sandbox account access to the caller's window station/desktop before CreateProcessWithLogonW (https://github.com/openai/codex/blob/1f41cc5d92/codex-rs/windows-sandbox-rs/src/elevated/runner_client.rs#L340-L365). Interactively, seclogon ACLs WinSta0 for the new logon; on the Session 0 service window station it doesn't, so user32 init fails with 0xC0000142 exactly as you observed. Notably, the crate's LaunchDesktop (sandbox_private_desktop) machinery exists but isn't wired into this spawn path at all, so your config setting never applies to the runner process.

The misleading error is a second bug: the pipe connect waits the full 15 s on recv_timeout without also waiting on pi.hProcess, so a child that dies at init still burns the timeout and reports timed out ... connecting runner pipe-in instead of the runner's exit code (same family as #38665).

Fix outline: (1) explicitly ACL the current window station + desktop for the sandbox SID (or set si.lpDesktop to a LaunchDesktop-created private desktop) before spawn; (2) race pipe-connect against WaitForSingleObject(pi.hProcess) and surface 0xC0000142 directly.

HIMBEERE01 · 6 days ago

Additional confirmation from a separate Windows ARM64 environment: this issue is still reproducible on the current alpha build.

Environment

  • Windows 11 Home, build 10.0.26200, ARM64
  • Windows OpenSSH / VS Code remote session
  • Codex CLI: 0.149.0-alpha.4
  • Codex IDE extension: 26.818.31338 (win32-arm64)
  • [windows] sandbox = "elevated"

Minimal reproduction

Running even a minimal command such as Get-Location through the native sandbox consistently ends with:

Failed to create unified exec process: timed out after 15000ms connecting runner pipe-in

The command runner is spawned and its named -in / -out pipes are visible, but it never connects. Windows System log records Application Popup, Event ID 26, for codex-command-runner-0.149.0-alpha.4.exe:

The application was unable to start correctly (0xc0000142).

The sandbox setup completes without reported errors, both sandbox accounts are enabled, runner source/cached executable hashes match, and no matching Defender, AppLocker, or Code Integrity block was found.

Compatibility checks

  • windows.sandbox_private_desktop=false: same pipe timeout
  • Temporary windows.sandbox="unelevated": PowerShell exits with -1073741502 (0xC0000142)
  • Unelevated direct cmd.exe /d /c cd: succeeds
  • Execution outside the sandbox succeeds immediately

The same behavior was also present with runner 0.148.0-alpha.21 / extension 26.818.22352, so it is not isolated to the latest update.

No user name, VM name, workspace path, repository, project code, or secrets are included. No persistent workaround or machine configuration change was left in place. Sanitized logs can be provided if useful.