Windows sandbox cannot recover when `deny_read_acl_state.json` becomes 22 NUL bytes after a system crash
Product and environment
- Codex desktop app on native Windows
- Observed app package:
OpenAI.Codex_26.715.8383.0_x64 - Windows 11 25H2, build
26200.8875 - Sandbox mode: ordinary native-Windows workspace-write execution
- State path:
%USERPROFILE%\.codex\.sandbox\deny_read_acl_state.json
Problem
After a Windows kernel crash, the Codex Windows sandbox can become persistently unusable because deny_read_acl_state.json contains exactly 22 zero bytes rather than JSON. Every ordinary sandbox setup tries to deserialize or reconcile this state and fails before the requested command process starts. Execution outside the sandbox still works because it bypasses this setup path.
This has now occurred three times on the same machine. Renaming the malformed file allows the next ordinary sandbox setup to regenerate valid state immediately, confirming that the requested command and repository are not the cause.
The upstream machine crashes are a separate Microsoft Wof.sys issue. This Codex report is about durability and recovery: an external crash can leave a reconstructible state artifact malformed, and Codex then turns that artifact into a persistent outage for every future sandboxed command.
Observed error and file contents
Ordinary commands fail before PowerShell or the requested process starts:
windows sandbox: helper_unknown_error: apply deny-read ACLs
The malformed file is:
Length: 22 bytes
Hex: 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
The intended empty serialized state is also 22 bytes:
{
"principals": {}
}
Reproduction using captured state
- Place a captured 22-NUL
deny_read_acl_state.jsonat the state path. - Run any ordinary sandboxed command from a valid workspace.
- Observe that sandbox setup fails before the requested process starts.
- Preserve and rename the malformed file.
- Run an ordinary sandboxed command again.
- Codex regenerates a valid 22-byte JSON file and the command starts successfully.
This recovery has been repeated after multiple crashes.
Evidence from three incidents
| Incident | State length | State content | Write-to-reboot interval | Result after reboot |
|---|---:|---|---:|---|
| 1 | 22 bytes | all NUL | ~20.6 seconds | every ordinary sandbox setup failed |
| 2 | 22 bytes | all NUL | ~17.3 seconds | same |
| 3 | 22 bytes | all NUL | 17.364 seconds | same |
The first two Windows minidumps independently identify the upstream crashes as bugcheck 0x139/A in Wof!WofPreDirectoryControlCallback+0x695, with the same Microsoft failure hash. The third Windows event is also 0x139/A; its dump has not yet been independently analyzed. Those kernel details establish the external-crash context, but they are not required to reproduce Codex's malformed-state failure.
Relevant implementation
The current Windows deny-read state implementation serializes with serde_json::to_vec_pretty and persists using a direct std::fs::write(path, bytes):
codex-rs/windows-sandbox-rs/src/deny_read_state.rs
The observed implementation does not provide:
- same-directory temporary-file creation followed by atomic replacement;
- explicit durable flushing before publication;
- validation of the newly written file before replacing the prior state;
- malformed-state quarantine and safe reconstruction;
- an interprocess lock around state reconciliation.
Regardless of the upstream kernel fault, a malformed reconstructible state file should not permanently disable sandbox setup.
Expected behavior
- A crash during or shortly after persistence should leave either the previous valid state or a complete new state.
- If state is malformed, setup should quarantine it for diagnostics, reconstruct safe state, and continue or emit a targeted actionable diagnostic.
- A corrupt reconstructible state artifact should not prevent every sandboxed command from launching indefinitely.
Requested fix
- Serialize and validate the complete next state in memory.
- Write it to a unique temporary file in the same directory.
- Flush the temporary file durably (
sync_allor the appropriate Windows equivalent). - Atomically replace the destination while preserving the previous valid file until publication.
- Coordinate writers with an interprocess mutex or equivalent lock.
- On deserialization failure, quarantine the malformed file and safely reconstruct state.
- Report a specific malformed-state diagnostic rather than the generic ACL-application error.
Privacy
This public report intentionally excludes usernames, repository names and paths, thread IDs, raw dumps, .codex databases, sandbox logs, credentials, and secrets. Sanitized debugger conclusions can be supplied publicly; raw evidence can be offered to OpenAI through a private channel if requested.
5 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
The primary addition this report provides is the “why it happens”. I have provided concrete evidence that it happens when windows crashes. I have also provided the fix. This should help prevent it in the future.
I have separately provided Microsoft with the relevant report on the Windows crash.
Independent confirmation from another native Windows Codex Desktop machine.
Environment
Microsoft Windows NT 10.0.26200.026.715.10079.026.715.3651.0Timeline and evidence
All times below are local (
Europe/Oslo) on 2026-07-18:01:40:13, the active Codex sandbox log output became NUL-filled while the helper was updating sandbox state.deny_read_acl_state.jsonreceived a last-write timestamp of01:40:15.01:40:45.The repeated error was:
The preserved malformed state has:
It contains no paths, usernames, credentials, tokens, or other data—only 22 NUL bytes. The file can be supplied if useful, although the size, hash, and byte description fully characterize it.
Recovery confirmation
Moving only the malformed state file to a
.bakpath allowed the next ordinary sandbox setup to regenerate:setup_error.jsondisappeared, and ordinary sandboxed PowerShell, Git reads,rg, Node, and workspace writes immediately succeeded again. A disposable write probe was created and removed successfully.This independently confirms that:
I did not analyze the Windows minidump; the relevant Codex defect is the persistent outage caused by failure to recover reconstructible local state. This also corroborates the recovery behavior described in #34276.
Follow-up from the same Windows machine after recovering the corrupt ACL-state file: I hit a second, reproducible workspace-write failure that may help isolate the ACL refresh path.
Inside a Codex-managed Git worktree declared as the writable root:
apply_patchin the same directory could be read but not rewritten by the same formatter:icaclsshowed that the parent directory had an inheritable(OI)(CI)(M)workspace-grant ACE and the pre-existing file had the corresponding inherited(I)(M)ACE. The newly created/replaced file was missing only that workspace-grant ACE; its normalCodexSandboxUsers:(I)(M)and other inherited entries were present.This looks consistent with
apply_patchcreating or atomically replacing a file with a DACL that does not retain the per-workspace grant marker, even though the parent ACE is inheritable. It also explains why using a separate worktree did not eliminate all sandbox failures: Git isolation was correct, but the newly created files themselves became unwritable to later sandboxed processes.I redacted machine-local account names and SIDs here; I can provide the full
icaclsbefore/after output if useful.Confirming the exact 22-NUL corruption and persistent recovery failure on a newer Codex Desktop build, with explicit user approval to share these sanitized diagnostics.
Environment:
OpenAI.Codex_26.730.8199.0_x64CODEX_HOMEon a local NTFS driveCurrent state:
.sandbox/deny_read_acl_state.jsonlength: 22 bytes0x006A4875DDACEAA91FB3369F0F6D962F77442DAF1B1D97733457D12BCABDF79441The sandbox log repeatedly records:
On 2026-08-06 the same sequence recurred many times during command startup/refresh. The sandbox never recovers or quarantines/regenerates the reconstructible state file.
User-visible impact in Desktop:
This machine also shows the permission-persistence symptom in #36497: after restart, active tasks are effectively
workspace-write/on-requestdespite selecting Full access, which makes the corrupt-state retry path especially visible as repeated approvals.No credentials, transcripts, databases, usernames, thread IDs, or private project paths are attached.