Windows Codex app: elevated sandbox cannot recover orphaned SYSTEM-DPAPI credentials (CryptUnprotectData 0x8009000B)

Open 💬 5 comments Opened Jul 28, 2026 by ColeRunsDiagnostics

What version of the Codex App are you using (From “About Codex” dialog)?

ChatGPT Windows app: 26.721.41059

What subscription do you have?

Plus

What platform is your computer?

Microsoft Windows NT 10.0.26200.0 x64 OS revision 26100.8875

What issue are you seeing?

Every Codex task fails before any command process initializes:

execution error: Io(Custom {
  kind: Other,
  error: "windows sandbox: CryptUnprotectData failed: 2148073483"
})
Decimal 2148073483 equals 0x8009000B.
No shell, Git, or filesystem command executes. Even Get-Location,
Get-Date, whoami, and git --version remain unexecuted.



### What steps can reproduce the bug?

Minimal reproduction
1.	Open the Codex Windows app using native Windows sandbox mode.
2.	Use a disposable Git repository:
C:\Temp\CodexTest
3.	Ask Codex to run Get-Location or git --version.
4.	Sandbox initialization fails before process creation with the error above.
The failure reproduces:
•	after multiple Windows restarts;
•	after app reset and reinstall;
•	when launching the app as Administrator;
•	in a disposable repository;
•	under a separate newly created local administrator account;
•	after the unrelated platform outage was resolved;
•	across recent app builds.

<img width="952" height="740" alt="Image" src="https://github.com/user-attachments/assets/d2ca938e-53ec-4bbb-9a1c-d7e11b0a29c5" />
<img width="607" height="572" alt="Image" src="https://github.com/user-attachments/assets/ec2bcbae-b13d-45c4-b6c9-308ae8d09ad3" />

### What is the expected behavior?

Expected behavior
When Codex-specific DPAPI-protected sandbox credentials cannot be decrypted
because their original SYSTEM master key is unavailable, setup should safely
regenerate the Codex-created users and their credential state.
Actual behavior
Sandbox initialization aborts permanently, and app reset, reinstall, elevated
launch, restarts, and a separate Windows account do not recover it.

### Additional information

Correlated Windows DPAPI evidence
Immediately after reproducing the failure, the enabled
Microsoft-Windows-Crypto-DPAPI/Operational log records:
Event 8198
DPAPI Unprotect failed
Status: 0x8009000B
ReasonForFailure: Could not get the master key
Related events at the identical timestamp and ActivityID show:
Security UserID: S-1-5-18
ProcessID: 1224
Process: lsass.exe
MasterKeyGUID: {REDACTED}
A read-only search of:
C:\Windows\System32\Microsoft\Protect\S-1-5-18
shows that the referenced master-key GUID is absent.
The SYSTEM DPAPI store itself is populated with multiple non-zero master-key
files and valid Preferred records, so this does not appear to be a generally
empty or destroyed SYSTEM DPAPI store.
Sandbox-account state
Both documented sandbox users exist and are enabled:
CodexSandboxOffline
PasswordLastSet: 7/25/2026 1:33:47 AM
LastLogon:       7/25/2026 1:38:40 AM

CodexSandboxOnline
PasswordLastSet: 7/25/2026 1:33:47 AM
LastLogon:       none
This indicates setup provisioned both accounts and successfully logged on with
the Offline account once.
Documented log behavior
The documented log:
%USERPROFILE%\.codex\.sandbox\sandbox.log
has not updated since May 15, 2026. Current initialization failures occur before
that log records anything.
Architectural connection
OpenAI’s “Building the Codex Windows Sandbox” article explains that the elevated
sandbox creates CodexSandboxOffline and CodexSandboxOnline, stores their
credentials encrypted with DPAPI, and later decrypts those credentials before
launching codex-command-runner.exe through CreateProcessWithLogonW.
The observed failure appears to occur at that exact boundary:
stored sandbox-user credential
→ SYSTEM CryptUnprotectData
→ referenced master key unavailable
→ command runner never launches
→ sandbox initialization aborts

<img width="713" height="315" alt="Image" src="https://github.com/user-attachments/assets/0c378379-99db-4828-8ce3-696e3477cd24" />
<img width="377" height="217" alt="Image" src="https://github.com/user-attachments/assets/8348d389-266b-4e91-a579-cb1790a38543" />

View original on GitHub ↗

5 Comments

glook9001 · 1 month ago

they are going to their methyos soyboy moment of their own with this snadboxing shit

ColeRunsDiagnostics · 22 days ago

Update (Aug. 5, 2026)

<html>
<body>
<!--StartFragment--><html><head></head><body><h2><span>Investigation update — two distinct sandbox state failures identified and locally resolved</span></h2><p><span>I have now restored full Windows sandbox operation and can separate this incident into two distinct, sequential failures:</span></p><ol start="1"><li><p><span>An existing </span><code><span>sandbox_users.json</span></code><span> contained DPAPI-protected sandbox credentials that could no longer be decrypted.</span></p></li><li><p><span>After those credentials were deliberately regenerated, sandbox setup progressed further but failed because </span><code><span>setup_marker.json</span></code><span> was unreadable by the normal invoking Windows user.</span></p></li></ol><p><span>These were sequential blockers. The marker failure was hidden until the credential-store failure was removed.</span></p><h3><span>Executive assessment</span></h3><p><span>The original </span><code><span>CryptUnprotectData failed: 2148073483</span></code><span> condition did not disappear merely because an application update was installed.</span></p><p><span>It persisted until I deliberately moved the existing:</span></p><pre><code><span>%USERPROFILE%\.codex\.sandbox-secrets\sandbox_users.json</span></code></pre><p><span>aside and allowed Codex to create a new credential store.</span></p><p><span>Immediately after that regeneration:</span></p><ul><li><p><span>both offline and online sandbox credential entries existed;</span></p></li><li><p><span>each password field decoded to a 246-byte DPAPI-protected blob;</span></p></li><li><p><span>both blobs decrypted successfully under the current Windows user;</span></p></li><li><p><span>each produced a 24-byte plaintext password;</span></p></li><li><p><span>the next sandbox attempt no longer failed at </span><code><span>CryptUnprotectData</span></code><span>;</span></p></li><li><p><span>execution advanced to a later </span><code><span>orchestrator_helper_incomplete</span></code><span> / setup-marker failure.</span></p></li></ul><p><span>The second failure was then isolated to:</span></p><pre><code><span>%USERPROFILE%\.codex\.sandbox\setup_marker.json</span></code></pre><p><span>The current setup helper created this marker and reported successful completion, but the normal Codex process could not read the resulting file. Restoring access for the invoking Windows account made the marker immediately readable and restored sandbox operation.</span></p><p><span>The final recovery was verified through sandbox initialization, a disposable filesystem lifecycle, an application restart, and a real repository write lifecycle with no residual changes.</span></p><div><hr></div><h2><span>Phase 1: isolating the DPAPI credential failure</span></h2><p><span>The original failure occurred before any command process initialized:</span></p><pre><code><span>windows sandbox: CryptUnprotectData failed: 2148073483</span></code></pre><p><span>Decimal </span><code><span>2148073483</span></code><span> is </span><code><span>0x8009000B</span></code><span>, </span><code><span>NTE_BAD_KEY_STATE</span></code><span>.</span></p><p><span>The original issue also documented correlated Windows DPAPI telemetry:</span></p><pre><code><span>Event 8198
DPAPI Unprotect failed
Status: 0x8009000B
ReasonForFailure: Could not get the master key
Security UserID: S-1-5-18
Process: lsass.exe</span></code></pre><p><span>The referenced master-key GUID was absent from:</span></p><pre><code><span>C:\Windows\System32\Microsoft\Protect\S-1-5-18</span></code></pre><p><span>The broader SYSTEM DPAPI store was populated, so the evidence did not indicate a completely empty or destroyed DPAPI store. It instead suggested that the specific protected data referenced a key that was no longer available.</span></p><h3><span>Credential-scope comparison</span></h3><p><span>The two Codex credential systems were tested separately:</span></p><pre><code><span>%USERPROFILE%\.codex\auth.json
%USERPROFILE%\.codex\.sandbox-secrets\sandbox_users.json</span></code></pre><p><code><span>auth.json</span></code><span> was readable and was not the failing credential system.</span></p><p><span>The existing </span><code><span>sandbox_users.json</span></code><span> contained entries for:</span></p><pre><code><span>CodexSandboxOffline
CodexSandboxOnline</span></code></pre><p><span>Both stored password blobs failed DPAPI decryption with “Key not valid for use in specified state.”</span></p><p><span>As a control, an unrelated Chromium DPAPI-protected key belonging to the Codex application profile decrypted successfully under the same Windows account. That was important evidence: DPAPI was not generally nonfunctional for this Windows profile. The failure was isolated to the stored sandbox-password blobs.</span></p><h3><span>Working theory and targeted intervention</span></h3><p><span>The working theory was that the existing sandbox-password blobs had become stale, orphaned, corrupted, or incompatible with the security context in which Codex now attempted to decrypt them.</span></p><p><span>Possible upstream explanations remain:</span></p><ul><li><p><span>the credentials were protected under a different Windows security context;</span></p></li><li><p><span>a prior Codex build wrote them using a different DPAPI context or lifecycle;</span></p></li><li><p><span>a migration retained blobs after the corresponding DPAPI master key became unavailable;</span></p></li><li><p><span>reinstall/update behavior preserved credentials that should have been invalidated;</span></p></li><li><p><span>the application lacked an automatic recovery path when </span><code><span>CryptUnprotectData</span></code><span> returned </span><code><span>NTE_BAD_KEY_STATE</span></code><span>.</span></p></li></ul><p><span>Rather than modify DPAPI master keys, local-account password data, the SAM, or </span><code><span>auth.json</span></code><span>, I performed a narrow and reversible test:</span></p><ol start="1"><li><p><span>Fully stopped ChatGPT/Codex.</span></p></li><li><p><span>Moved—not deleted—the existing </span><code><span>sandbox_users.json</span></code><span> to a timestamped backup.</span></p></li><li><p><span>Restarted the application.</span></p></li><li><p><span>Reran elevated Windows sandbox setup.</span></p></li><li><p><span>Verified that Codex created a new </span><code><span>sandbox_users.json</span></code><span>.</span></p></li><li><p><span>Independently tested the new blobs without displaying their protected or plaintext values.</span></p></li></ol><p><span>The replacement file was created on August 5, 2026 at approximately 12:07 PM:</span></p><pre><code><span>Length: 828 bytes
CreationTime: 8/5/2026 12:07:01 PM
LastWriteTime: 8/5/2026 12:07:01 PM</span></code></pre><p><span>Both new credential entries passed DPAPI decryption:</span></p><pre><code><span>Mode: offline
ProtectedBytes: 246
Result: Decryptable
PlaintextLength: 24

Mode: online
ProtectedBytes: 246
Result: Decryptable
PlaintextLength: 24</span></code></pre><p><span>The very next smoke test advanced past DPAPI and failed later with:</span></p><pre><code><span>windows sandbox: orchestrator_helper_incomplete:
setup helper exited successfully before setup completed</span></code></pre><p><span>It also began reporting:</span></p><pre><code><span>sandbox setup required:
sandbox setup marker missing or incompatible</span></code></pre><p><span>This establishes the observed causal transition:</span></p><pre><code><span>Old sandbox_users.json present

Both protected sandbox-password blobs fail DPAPI decryption

Every sandbox attempt stops at CryptUnprotectData

Old credential file moved aside

Codex generates new offline and online credentials

Both new blobs decrypt successfully

CryptUnprotectData error disappears

Sandbox reaches the subsequent setup-marker failure</span></code></pre><h3><span>Release-timeline qualification for the DPAPI finding</span></h3><p><span>The update history matters:</span></p><ul><li><p><span>The failure was present on the original reported 26.721 application line. The About dialog reported </span><code><span>26.721.41059</span></code><span>; the installed MSIX package observed during diagnostics was </span><code><span>26.721.4979.0</span></code><span>.</span></p></li><li><p><span>The Microsoft Store subsequently delivered </span><code><span>26.727.6591.0</span></code><span>.</span></p></li><li><p><span>The old </span><code><span>sandbox_users.json</span></code><span> still contained two undecryptable blobs after that update. Therefore, </span><code><span>26.727.6591.0</span></code><span> did not automatically recover the existing broken credential state.</span></p></li><li><p><span>The credential store was deliberately moved and regenerated while investigating that state.</span></p></li><li><p><code><span>26.730.8199.0</span></code><span> was installed later, after the broken credential file had already been replaced.</span></p></li></ul><p><span>Accordingly:</span></p><ul><li><p><span>The evidence supports that deliberate credential regeneration resolved the local DPAPI failure.</span></p></li><li><p><span>The evidence does not support attributing that recovery to </span><code><span>26.727</span></code><span>.</span></p></li><li><p><span>Because </span><code><span>26.730</span></code><span> was installed after regeneration, this machine cannot determine whether </span><code><span>26.730</span></code><span> contains code capable of recovering the old blobs; the old broken store was no longer active when that build ran.</span></p></li><li><p><span>It remains possible that Codex changed credential-generation or migration behavior during this release window. If so, the release still did not provide automatic recovery from an already-present undecryptable </span><code><span>sandbox_users.json</span></code><span> in the state actually observed.</span></p></li></ul><p><span>This is the product behavior I believe engineering should investigate: </span><code><span>NTE_BAD_KEY_STATE</span></code><span> on Codex-owned sandbox credentials currently appears capable of creating a permanent startup failure instead of triggering a safe, narrowly scoped credential regeneration path.</span></p><div><hr></div><h2><span>Phase 2: setup completed, but its marker was unreadable</span></h2><p><span>Once the credential store was regenerated, Codex consistently progressed into elevated sandbox setup.</span></p><p><span>The current helper successfully performed or reported:</span></p><ul><li><p><span>sandbox-user provisioning;</span></p></li><li><p><span>WFP configuration;</span></p></li><li><p><span>installation of 12 WFP filters;</span></p></li><li><p><span>write-root ACL processing;</span></p></li><li><p><span>read-ACL processing;</span></p></li><li><p><span>creation of a version-5 </span><code><span>setup_marker.json</span></code><span>;</span></p></li><li><p><code><span>setup binary completed</span></code><span>;</span></p></li><li><p><span>successful helper exit.</span></p></li></ul><p><span>However, the normal command runner never launched. The next command again reported:</span></p><pre><code><span>sandbox setup marker missing or incompatible</span></code></pre><p><span>followed by:</span></p><pre><code><span>orchestrator_helper_incomplete:
setup helper exited successfully before setup completed</span></code></pre><h3><span>Build-integrity verification</span></h3><p><span>At this stage, the installed and active package was:</span></p><pre><code><span>OpenAI.Codex_26.730.8199.0_x64__2p2nqsd0c76g0
Status: Ok</span></code></pre><p><span>Every active ChatGPT/Codex process used the </span><code><span>26.730.8199.0</span></code><span> package path.</span></p><p><span>The current cached executables matched their package copies by size and SHA-256:</span></p>
Binary | Size | SHA-256
-- | -- | --
codex.exe | 363,706,672 | FA960EC081BEC3629F40C63ED610EBC49C7E5E077DFB42322B08CB6D460F0B8A
codex-code-mode-host.exe | 56,721,712 | 910159E6F9460103C846D7723A2EF82BED90DE45C582E0E004DC2CE7D10A3C3F
codex-command-runner.exe | 1,302,320 | D2C2E8332EC93CEB048E924A4C728932B3D5AF247B98FE7C9C2DDFC2ADFA33F7
codex-windows-sandbox-setup.exe | 8,808,240 | 43B2658B5AB5D0A886E78CEE0510E605361EB33FBAC7D1F1DC7A195E58E6A944

<p><span>The older runtime-cache directory contained only </span><code><span>rg.exe</span></code><span>, not an older </span><code><span>codex.exe</span></code><span>, command runner, code-mode host, or setup helper.</span></p><p><span>This evidence rules out a mixed package/current-cache explanation for the behavior observed under </span><code><span>26.730.8199.0</span></code><span>.</span></p><h3><span>File-specific ACL evidence</span></h3><p><span>During a controlled setup attempt at approximately 12:49 PM, the log sequence was:</span></p><pre><code><span>12:49:08.382 codex.exe:
sandbox setup required: sandbox setup marker missing or incompatible

12:49:11.140:
ensuring sandbox users offline=CodexSandboxOffline online=CodexSandboxOnline

12:49:12.007:
WFP setup succeeded for CodexSandboxOffline with 12 installed filters

12:49:12.269:
read-acl-only mode: applying read ACLs

12:49:12.271 codex-windows-sandbox-setup.exe:
setup binary completed

12:49:12.279:
read ACL run completed</span></code></pre><p><span>The helper freshly recreated:</span></p><pre><code><span>%USERPROFILE%\.codex\.sandbox\setup_marker.json</span></code></pre><p><span>Immediately afterward:</span></p><ul><li><p><span>the file existed;</span></p></li><li><p><span>its timestamp showed that it had just been rewritten;</span></p></li><li><p><code><span>Get-Content</span></code><span> failed with Access Denied;</span></p></li><li><p><code><span>Get-Acl</span></code><span> failed with </span><code><span>UnauthorizedAccessException</span></code><span>;</span></p></li><li><p><code><span>icacls</span></code><span> reported Access Denied and processed zero files;</span></p></li><li><p><span>the normal Codex process classified the marker as “missing or incompatible”;</span></p></li><li><p><span>no </span><code><span>codex-command-runner.exe</span></code><span> launch followed.</span></p></li></ul><p><span>The parent </span><code><span>.sandbox</span></code><span> directory remained owned by the signed-in user and granted that user Full Control. The access failure was therefore specific to the newly created marker, rather than the parent directory.</span></p><p><span>Because Windows denied even ACL inspection from the normal account, I could not capture a complete pre-repair SDDL for the defective file. I therefore cannot state exactly which ACE was missing or protected. What is established is that the fresh file was unreadable, while its parent was accessible.</span></p><h3><span>Targeted ACL repair</span></h3><p><span>A narrowly scoped elevated repair was applied only to </span><code><span>setup_marker.json</span></code><span>.</span></p><p><span>Before mutation, the procedure:</span></p><ul><li><p><span>created a timestamped backup using backup mode;</span></p></li><li><p><span>preserved the file’s content, ownership, and ACL metadata;</span></p></li><li><p><span>separately saved the original ACL with </span><code><span>icacls /save</span></code><span>;</span></p></li><li><p><span>refused to continue if the backup failed.</span></p></li></ul><p><span>The repair then granted the invoking account Full Control without changing ownership.</span></p><p><span>Observed result:</span></p><pre><code><span>ROBOCOPY_EXIT=1
ICACLS_SAVE_EXIT=0
INITIAL_GRANT_EXIT=0
OWNER_CHANGED=False
MARKER_READABLE=True
MARKER_VERSION=5
MARKER_LENGTH=255</span></code></pre><p><span>The repaired ACL contained explicit Full Control for the invoking Windows user. Ownership remained:</span></p><pre><code><span>BUILTIN\Administrators</span></code></pre><p><span>Immediately after this one-file ACL repair:</span></p><ul><li><p><span>Codex accepted the existing marker;</span></p></li><li><p><span>sandbox initialization succeeded;</span></p></li><li><p><span>the setup loop stopped;</span></p></li><li><p><code><span>codex-command-runner.exe</span></code><span> launched;</span></p></li><li><p><span>no further DPAPI error occurred.</span></p></li></ul><p><span>This establishes the second causal transition:</span></p><pre><code><span>26.730 helper creates/rewrites version-5 marker

Marker exists but normal invoking user cannot read it

Codex reports marker “missing or incompatible”

Setup repeats and orchestrator_helper_incomplete is returned

Explicit access restored on that marker only

Marker becomes readable and remains valid JSON

Codex accepts marker

Command runner launches and sandbox operations succeed</span></code></pre><div><hr></div><h2><span>Cross-version and multi-user evidence for the marker ACL issue</span></h2><p><span>The marker behavior is not unique to this machine or newly attributable to </span><code><span>26.730</span></code><span>.</span></p><p><span>Related public reports include:</span></p><ul><li><p><a href="https://github.com/openai/codex/issues/30445"><span>#30445 — Windows sandbox setup marker ACL prevents Codex from starting sandbox after UAC setup</span></a><span>, reported June 28, 2026 on package </span><code><span>26.623.5546.0</span></code><span>. The reporter found that granting the current user access to </span><code><span>setup_marker.json</span></code><span> immediately restored sandbox commands.</span></p></li><li><p><a href="https://github.com/openai/codex/issues/35407"><span>#35407 — Windows Desktop 26.721 repeats elevated sandbox setup; marker rewritten but unreadable/rejected</span></a><span>, reported July 25, 2026 on package </span><code><span>26.721.4979.0</span></code><span>. That report captured the same successful-helper/setup-loop behavior and an unreadable freshly rewritten marker.</span></p></li><li><p><a href="https://github.com/openai/codex/issues/23712"><span>#23712 — Windows Desktop repeatedly launches elevated setup helper</span></a><span>, reported May 20, 2026 on app version </span><code><span>26.513.40821</span></code><span>, records the earlier repeated “marker missing or incompatible” setup pattern, although it does not independently prove the marker ACL cause.</span></p></li></ul><p><span>My reproduction on </span><code><span>26.730.8199.0</span></code><span> extends the directly evidenced ACL problem across at least:</span></p><pre><code><span>26.623.5546.0
26.721.4979.0
26.730.8199.0</span></code></pre><p><span>Therefore:</span></p><ul><li><p><span>I do not believe </span><code><span>26.730</span></code><span> introduced the marker ACL defect.</span></p></li><li><p><code><span>26.730</span></code><span> did not repair it on this machine.</span></p></li><li><p><span>The evidence instead points to a longer-lived Windows sandbox marker-creation or ACL-inheritance issue that survived multiple releases.</span></p></li><li><p><span>The setup-loop symptom may extend further back, but only reports that directly tested marker readability should be treated as confirmation of the same root cause.</span></p></li></ul><p><span>The </span><code><span>26.727</span></code><span> build produced the setup-marker loop immediately after credential regeneration, but I did not capture the marker’s ACL in that build. The file-specific Access Denied condition was directly proven after the subsequent </span><code><span>26.730</span></code><span> update. It is therefore reasonable to say the same defect may have been present in </span><code><span>26.727</span></code><span>, but that specific build-level attribution is not proven by my data.</span></p><div><hr></div><h2><span>Post-repair validation</span></h2><h3><span>Disposable filesystem lifecycle</span></h3><p><span>A complete smoke test ran only within:</span></p><pre><code><span>C:\Temp\CodexTest</span></code></pre><p><span>Verified:</span></p><ul><li><p><span>sandbox initialization;</span></p></li><li><p><span>file creation;</span></p></li><li><p><span>exact-content write;</span></p></li><li><p><span>exact-content readback;</span></p></li><li><p><span>rename;</span></p></li><li><p><span>renamed-file verification;</span></p></li><li><p><span>deletion;</span></p></li><li><p><span>confirmation that no test artifacts remained;</span></p></li><li><p><span>no errors or warnings;</span></p></li><li><p><span>no access or modification outside the disposable directory.</span></p></li></ul><h3><span>Persistence across application restart</span></h3><p><span>After fully restarting the application:</span></p><ul><li><p><span>the “Try Windows setup again” condition did not return;</span></p></li><li><p><span>Codex accepted the existing setup state;</span></p></li><li><p><span>another sandbox task launched normally.</span></p></li></ul><h3><span>Repository lifecycle</span></h3><p><span>A controlled disposable-file test inside a real Git repository verified:</span></p><ul><li><p><span>initial </span><code><span>git status --short</span></code><span> recorded;</span></p></li><li><p><span>disposable file created;</span></p></li><li><p><span>exact content </span><code><span>FSBDL_WRITE_TEST_1</span></code><span> confirmed;</span></p></li><li><p><span>content changed to </span><code><span>FSBDL_WRITE_TEST_2</span></code><span> and confirmed;</span></p></li><li><p><span>file renamed;</span></p></li><li><p><span>file deleted;</span></p></li><li><p><span>both disposable paths absent afterward;</span></p></li><li><p><span>final </span><code><span>git status --short</span></code><span> exactly matched the initial state;</span></p></li><li><p><span>no existing repository file was modified;</span></p></li><li><p><span>no elevated filesystem fallback was used.</span></p></li></ul><p><span>This demonstrates more than UI recovery: the sandbox command runner resumed safe repository operations end to end.</span></p><div><hr></div><h2><span>Confirmed findings, strongest theories, and remaining unknowns</span></h2><h3><span>Confirmed</span></h3><ol start="1"><li><p><span>The old offline and online password blobs in </span><code><span>sandbox_users.json</span></code><span> were not decryptable.</span></p></li><li><p><span>An unrelated Codex-profile DPAPI key remained decryptable, so DPAPI was not generally broken for the signed-in Windows account.</span></p></li><li><p><span>Moving the old credential JSON caused Codex to generate a fresh credential store.</span></p></li><li><p><span>Both new password blobs decrypted successfully.</span></p></li><li><p><span>The </span><code><span>CryptUnprotectData</span></code><span> error disappeared immediately after regeneration.</span></p></li><li><p><span>The next blocker was a freshly created </span><code><span>setup_marker.json</span></code><span> that the invoking user could not read.</span></p></li><li><p><span>The </span><code><span>26.730</span></code><span> package, active processes, and runtime cache were internally consistent.</span></p></li><li><p><span>Granting the invoking user access to only the marker made Codex accept it.</span></p></li><li><p><span>Sandbox initialization and command execution then succeeded.</span></p></li><li><p><span>The repair persisted through application restart and a repository lifecycle test.</span></p></li></ol><h3><span>Strongest supported theory</span></h3><p><span>The incident consisted of two independently recoverable Codex-owned state failures:</span></p><ul><li><p><span>stale, orphaned, or context-incompatible DPAPI-protected sandbox credentials without an automatic recovery path;</span></p></li><li><p><span>a setup-marker ACL defect that prevented the normal process from reading state created by the elevated helper.</span></p></li></ul><h3><span>Not established</span></h3><ol start="1"><li><p><span>The exact Codex version or lifecycle event that originally made the old DPAPI blobs unusable.</span></p></li><li><p><span>Whether the missing SYSTEM master key resulted from a Codex update, failed credential migration, reinstall/reset behavior, Windows state change, or another event.</span></p></li><li><p><span>Whether </span><code><span>26.730</span></code><span> contains any DPAPI recovery change; the broken credential file had already been replaced before that build was installed.</span></p></li><li><p><span>The exact defective pre-repair marker SDDL, because the normal user could not read the file or its ACL.</span></p></li><li><p><span>Whether every user experiencing </span><code><span>CryptUnprotectData</span></code><span> has the same credential-file condition.</span></p></li><li><p><span>Whether every “marker missing or incompatible” report is an ACL defect; some may have other causes.</span></p></li></ol><div><hr></div><h2><span>Engineering recommendations</span></h2><h3><span>Credential-store recovery</span></h3><p><span>When decrypting a Codex-owned sandbox password returns </span><code><span>0x8009000B</span></code><span> or indicates that the required master key is unavailable, setup should not remain permanently blocked.</span></p><p><span>A safe recovery path could:</span></p><ol start="1"><li><p><span>distinguish sandbox credentials from ChatGPT account authentication;</span></p></li><li><p><span>preserve or quarantine the unreadable </span><code><span>sandbox_users.json</span></code><span> for diagnostics;</span></p></li><li><p><span>regenerate only the Codex-created sandbox-account passwords and protected blobs;</span></p></li><li><p><span>update the corresponding local sandbox-account passwords;</span></p></li><li><p><span>verify that both new blobs can be decrypted in the context that will later launch the command runner;</span></p></li><li><p><span>surface a precise diagnostic if regeneration fails.</span></p></li></ol><p><span>At minimum, the UI should explain that the sandbox credential store is unreadable and offer a scoped repair. App reset/reinstall did not clear this state in the originally reported condition.</span></p><h3><span>Marker creation and validation</span></h3><p><span>The elevated setup helper should ensure that the normal invoking user can read and validate </span><code><span>setup_marker.json</span></code><span> after setup completes.</span></p><p><span>Potential safeguards:</span></p><ol start="1"><li><p><span>explicitly preserve or grant the invoking user SID when creating/replacing the marker;</span></p></li><li><p><span>validate the final marker using the same unelevated identity/context as the desktop runtime;</span></p></li><li><p><span>avoid replacing an inheritable file with one carrying a protected ACL that excludes the caller;</span></p></li><li><p><span>distinguish “file absent,” “invalid schema/version,” and “Access Denied” instead of collapsing all three into “missing or incompatible”;</span></p></li><li><p><span>do not report helper success until the final marker is readable and accepted by the consuming process.</span></p></li></ol><p><span>Please consider linking this issue with #30445 and #35407. The matching repair result across multiple users and multiple package generations makes the marker ACL behavior appear product-level rather than machine-specific.</span></p><h3><span>Current status</span></h3><p><span>The sandbox is operational on this machine after:</span></p><ol start="1"><li><p><span>deliberately regenerating </span><code><span>sandbox_users.json</span></code><span>; and</span></p></li><li><p><span>restoring access to </span><code><span>setup_marker.json</span></code><span>.</span></p></li></ol><p><span>I am retaining the old credential-store backup, marker backup, saved ACL data, repair transcript, and relevant logs in case engineering wants specific artifacts or a controlled follow-up test.</span></p><p><span>I do not recommend closing the issue solely because the local installation has recovered. Both recovery steps addressed Codex-owned state that the application did not repair automatically, and the marker ACL defect has independent cross-version reports from other users.</span></p></body></html><!--EndFragment-->
</body>
</html>## Investigation update — two distinct sandbox state failures identified and locally resolved

I have now restored full Windows sandbox operation and can separate the investigation into two distinct failures:

  1. An existing sandbox_users.json contained DPAPI-protected sandbox credentials that could no longer be decrypted.
  2. After those credentials were deliberately regenerated, sandbox setup progressed further but failed because setup_marker.json was unreadable by the normal invoking Windows user.

These were sequential blockers. The marker failure was hidden until the credential-store failure was removed.

Executive assessment

The original CryptUnprotectData failed: 2148073483 condition did not disappear merely because an application update was installed.

It persisted until I deliberately moved the existing:

%USERPROFILE%\.codex\.sandbox\setup_marker.json

aside and allowed Codex to create a new credential store.

Immediately after that regeneration:

  • both offline and online sandbox credential entries existed;
  • each password field decoded to a 246-byte DPAPI-protected blob;
  • both blobs decrypted successfully under the current Windows user;
  • each produced a 24-byte plaintext password;
  • the next sandbox attempt no longer failed at CryptUnprotectData;
  • execution advanced to a later orchestrator_helper_incomplete / setup-marker failure.

The second failure was then isolated to:

%USERPROFILE%\.codex\.sandbox-secrets\sandbox_users.json

The current setup helper created this marker and reported successful completion, but the normal Codex process could not read the resulting file. Restoring access for the invoking Windows account made the marker immediately readable and restored sandbox operation.

The final recovery was verified through sandbox initialization, a disposable filesystem lifecycle, an application restart, and a real repository write lifecycle with no residual changes.

---

Phase 1: isolating the DPAPI credential failure

The original failure occurred before any command process initialized:

windows sandbox: CryptUnprotectData failed: 2148073483

Decimal 2148073483 is 0x8009000B, NTE_BAD_KEY_STATE.

The original issue also documented correlated Windows DPAPI telemetry:

Event 8198
DPAPI Unprotect failed
Status: 0x8009000B
ReasonForFailure: Could not get the master key
Security UserID: S-1-5-18
Process: lsass.exe

The referenced master-key GUID was absent from:

C:\Windows\System32\Microsoft\Protect\S-1-5-18

The broader SYSTEM DPAPI store was populated, so the evidence did not indicate a completely empty or destroyed DPAPI store. It instead suggested that the specific protected data referenced a key that was no longer available.

Credential-scope comparison

The two Codex credential systems were tested separately:

%USERPROFILE%\.codex\auth.json
%USERPROFILE%\.codex\.sandbox-secrets\sandbox_users.json

auth.json was readable and was not the failing credential system.

The existing sandbox_users.json contained entries for:

CodexSandboxOffline
CodexSandboxOnline

Both stored password blobs failed DPAPI decryption with “Key not valid for use in specified state.”

As a control, an unrelated Chromium DPAPI-protected key belonging to the Codex application profile decrypted successfully under the same Windows account. That was important evidence: DPAPI was not generally nonfunctional for this Windows profile. The failure was isolated to the stored sandbox-password blobs.

Working theory and targeted intervention

The working theory was that the existing sandbox-password blobs had become stale, orphaned, corrupted, or incompatible with the security context in which Codex now attempted to decrypt them.

Possible upstream explanations remain:

  • the credentials were protected under a different Windows security context;
  • a prior Codex build wrote them using a different DPAPI context or lifecycle;
  • a migration retained blobs after the corresponding DPAPI master key became unavailable;
  • reinstall/update behavior preserved credentials that should have been invalidated;
  • the application lacked an automatic recovery path when CryptUnprotectData returned NTE_BAD_KEY_STATE.

Rather than modify DPAPI master keys, local-account password data, the SAM, or auth.json, I performed a narrow and reversible test:

  1. Fully stopped ChatGPT/Codex.
  2. Moved—not deleted—the existing sandbox_users.json to a timestamped backup.
  3. Restarted the application.
  4. Reran elevated Windows sandbox setup.
  5. Verified that Codex created a new sandbox_users.json.
  6. Independently tested the new blobs without displaying their protected or plaintext values.

The replacement file was created on August 5, 2026 at approximately 12:07 PM:

Length:        828 bytes
CreationTime:  8/5/2026 12:07:01 PM
LastWriteTime: 8/5/2026 12:07:01 PM

Both new credential entries passed DPAPI decryption:

Mode:            offline
ProtectedBytes:  246
Result:          Decryptable
PlaintextLength: 24

Mode:            online
ProtectedBytes:  246
Result:          Decryptable
PlaintextLength: 24

The very next smoke test advanced past DPAPI and failed later with:

windows sandbox: orchestrator_helper_incomplete:
setup helper exited successfully before setup completed

It also began reporting:

sandbox setup required:
sandbox setup marker missing or incompatible

This establishes the observed causal transition:

Old sandbox_users.json present
    ↓
Both protected sandbox-password blobs fail DPAPI decryption
    ↓
Every sandbox attempt stops at CryptUnprotectData
    ↓
Old credential file moved aside
    ↓
Codex generates new offline and online credentials
    ↓
Both new blobs decrypt successfully
    ↓
CryptUnprotectData error disappears
    ↓
Sandbox reaches the subsequent setup-marker failure

Release-timeline qualification for the DPAPI finding

The update history matters:

  • The failure was present on the original reported 26.721 application line. The About dialog reported 26.721.41059; the installed MSIX package observed during diagnostics was 26.721.4979.0.
  • The Microsoft Store subsequently delivered 26.727.6591.0.
  • The old sandbox_users.json still contained two undecryptable blobs after that update. Therefore, 26.727.6591.0 did not automatically recover the existing broken credential state.
  • The credential store was deliberately moved and regenerated while investigating that state.
  • 26.730.8199.0 was installed later, after the broken credential file had already been replaced.

Accordingly:

  • The evidence supports that deliberate credential regeneration resolved the local DPAPI failure.
  • The evidence does not support attributing that recovery to 26.727.
  • Because 26.730 was installed after regeneration, this machine cannot determine whether 26.730 contains code capable of recovering the old blobs; the old broken store was no longer active when that build ran.
  • It remains possible that Codex changed credential-generation or migration behavior during this release window. If so, the release still did not provide automatic recovery from an already-present undecryptable sandbox_users.json in the state actually observed.

This is the product behavior I believe engineering should investigate: NTE_BAD_KEY_STATE on Codex-owned sandbox credentials currently appears capable of creating a permanent startup failure instead of triggering a safe, narrowly scoped credential regeneration path.

---

Phase 2: setup completed, but its marker was unreadable

Once the credential store was regenerated, Codex consistently progressed into elevated sandbox setup.

The current helper successfully performed or reported:

  • sandbox-user provisioning;
  • WFP configuration;
  • installation of 12 WFP filters;
  • write-root ACL processing;
  • read-ACL processing;
  • creation of a version-5 setup_marker.json;
  • setup binary completed;
  • successful helper exit.

However, the normal command runner never launched. The next command again reported:

sandbox setup marker missing or incompatible

followed by:

orchestrator_helper_incomplete:
setup helper exited successfully before setup completed

Build-integrity verification

At this stage, the installed and active package was:

OpenAI.Codex_26.730.8199.0_x64__2p2nqsd0c76g0
Status: Ok

Every active ChatGPT/Codex process used the 26.730.8199.0 package path.

The current cached executables matched their package copies by size and SHA-256:

| Binary | Size | SHA-256 |
|---|---:|---|
| codex.exe | 363,706,672 | FA960EC081BEC3629F40C63ED610EBC49C7E5E077DFB42322B08CB6D460F0B8A |
| codex-code-mode-host.exe | 56,721,712 | 910159E6F9460103C846D7723A2EF82BED90DE45C582E0E004DC2CE7D10A3C3F |
| codex-command-runner.exe | 1,302,320 | D2C2E8332EC93CEB048E924A4C728932B3D5AF247B98FE7C9C2DDFC2ADFA33F7 |
| codex-windows-sandbox-setup.exe | 8,808,240 | 43B2658B5AB5D0A886E78CEE0510E605361EB33FBAC7D1F1DC7A195E58E6A944 |

The older runtime-cache directory contained only rg.exe, not an older codex.exe, command runner, code-mode host, or setup helper.

This evidence rules out a mixed package/current-cache explanation for the behavior observed under 26.730.8199.0.

File-specific ACL evidence

During a controlled setup attempt at approximately 12:49 PM, the log sequence was:

12:49:08.382 codex.exe:
sandbox setup required: sandbox setup marker missing or incompatible

12:49:11.140:
ensuring sandbox users offline=CodexSandboxOffline online=CodexSandboxOnline

12:49:12.007:
WFP setup succeeded for CodexSandboxOffline with 12 installed filters

12:49:12.269:
read-acl-only mode: applying read ACLs

12:49:12.271 codex-windows-sandbox-setup.exe:
setup binary completed

12:49:12.279:
read ACL run completed

The helper freshly recreated:

%USERPROFILE%\.codex\.sandbox\setup_marker.json

Immediately afterward:

  • the file existed;
  • its timestamp showed that it had just been rewritten;
  • Get-Content failed with Access Denied;
  • Get-Acl failed with UnauthorizedAccessException;
  • icacls reported Access Denied and processed zero files;
  • the normal Codex process classified the marker as “missing or incompatible”;
  • no codex-command-runner.exe launch followed.

The parent .sandbox directory remained owned by the signed-in user and granted that user Full Control. The access failure was therefore specific to the newly created marker, rather than the parent directory.

Because Windows denied even ACL inspection from the normal account, I could not capture a complete pre-repair SDDL for the defective file. I therefore cannot state exactly which ACE was missing or protected. What is established is that the fresh file was unreadable, while its parent was accessible.

Targeted ACL repair

A narrowly scoped elevated repair was applied only to setup_marker.json.

Before mutation, the procedure:

  • created a timestamped backup using backup mode;
  • preserved the file’s content, ownership, and ACL metadata;
  • separately saved the original ACL with icacls /save;
  • refused to continue if the backup failed.

The repair then granted the invoking account Full Control without changing ownership.

Observed result:

ROBOCOPY_EXIT=1
ICACLS_SAVE_EXIT=0
INITIAL_GRANT_EXIT=0
OWNER_CHANGED=False
MARKER_READABLE=True
MARKER_VERSION=5
MARKER_LENGTH=255

The repaired ACL contained explicit Full Control for:

the invoking Windows user

Ownership remained:

BUILTIN\Administrators

Immediately after this one-file ACL repair:

  • Codex accepted the existing marker;
  • sandbox initialization succeeded;
  • the setup loop stopped;
  • codex-command-runner.exe launched;
  • no further DPAPI error occurred.

This establishes the second causal transition:

26.730 helper creates/rewrites version-5 marker
    ↓
Marker exists but normal invoking user cannot read it
    ↓
Codex reports marker “missing or incompatible”
    ↓
Setup repeats and orchestrator_helper_incomplete is returned
    ↓
Explicit access restored on that marker only
    ↓
Marker becomes readable and remains valid JSON
    ↓
Codex accepts marker
    ↓
Command runner launches and sandbox operations succeed

---

Cross-version and multi-user evidence for the marker ACL issue

The marker behavior is not unique to this machine or newly attributable to 26.730.

Related public reports include:

My reproduction on 26.730.8199.0 extends the directly evidenced ACL problem across at least:

26.623.5546.0
26.721.4979.0
26.730.8199.0

Therefore:

  • I do not believe 26.730 introduced the marker ACL defect.
  • 26.730 did not repair it on this machine.
  • The evidence instead points to a longer-lived Windows sandbox marker-creation or ACL-inheritance issue that survived multiple releases.
  • The setup-loop symptom may extend further back, but only reports that directly tested marker readability should be treated as confirmation of the same root cause.

The 26.727 build produced the setup-marker loop immediately after credential regeneration, but I did not capture the marker’s ACL in that build. The file-specific Access Denied condition was directly proven after the subsequent 26.730 update. It is therefore reasonable to say the same defect may have been present in 26.727, but that specific build-level attribution is not proven by my data.

---

Post-repair validation

Disposable filesystem lifecycle

A complete smoke test ran only within:

C:\Temp\CodexTest

Verified:

  • sandbox initialization;
  • file creation;
  • exact-content write;
  • exact-content readback;
  • rename;
  • renamed-file verification;
  • deletion;
  • confirmation that no test artifacts remained;
  • no errors or warnings;
  • no access or modification outside the disposable directory.

Persistence across application restart

After fully restarting the application:

  • the “Try Windows setup again” condition did not return;
  • Codex accepted the existing setup state;
  • another sandbox task launched normally.

Repository lifecycle

A controlled disposable-file test inside a real Git repository verified:

  • initial git status --short recorded;
  • disposable file created;
  • exact content FSBDL_WRITE_TEST_1 confirmed;
  • content changed to FSBDL_WRITE_TEST_2 and confirmed;
  • file renamed;
  • file deleted;
  • both disposable paths absent afterward;
  • final git status --short exactly matched the initial state;
  • no existing repository file was modified;
  • no elevated filesystem fallback was used.

This was the first successful end-to-end repository operation since the original CryptUnprotectData failure began.

This demonstrates more than UI recovery: the sandbox command runner resumed safe repository operations end to end.

---

Confirmed findings, strongest theories, and remaining unknowns

Confirmed

  1. The old offline and online password blobs in sandbox_users.json were not decryptable.
  2. An unrelated Codex-profile DPAPI key remained decryptable, so DPAPI was not generally broken for the signed-in Windows account.
  3. Moving the old credential JSON caused Codex to generate a fresh credential store.
  4. Both new password blobs decrypted successfully.
  5. The CryptUnprotectData error disappeared immediately after regeneration.
  6. The next blocker was a freshly created setup_marker.json that the invoking user could not read.
  7. The 26.730 package, active processes, and runtime cache were internally consistent.
  8. Granting the invoking user access to only the marker made Codex accept it.
  9. Sandbox initialization and command execution then succeeded.
  10. The repair persisted through application restart and a repository lifecycle test.

Strongest supported theory

The incident consisted of two independently recoverable Codex-owned state failures:

  • stale, orphaned, or context-incompatible DPAPI-protected sandbox credentials without an automatic recovery path;
  • a setup-marker ACL defect that prevented the normal process from reading state created by the elevated helper.

Not established

  1. The exact Codex version or lifecycle event that originally made the old DPAPI blobs unusable.
  2. Whether the missing SYSTEM master key resulted from a Codex update, failed credential migration, reinstall/reset behavior, Windows state change, or another event.
  3. Whether 26.730 contains any DPAPI recovery change; the broken credential file had already been replaced before that build was installed.
  4. The exact defective pre-repair marker SDDL, because the normal user could not read the file or its ACL.
  5. Whether every user experiencing CryptUnprotectData has the same credential-file condition.
  6. Whether every “marker missing or incompatible” report is an ACL defect; some may have other causes.

---

Engineering recommendations

Credential-store recovery

When decrypting a Codex-owned sandbox password returns 0x8009000B or indicates that the required master key is unavailable, setup should not remain permanently blocked.

A safe recovery path could:

  1. distinguish sandbox credentials from ChatGPT account authentication;
  2. preserve or quarantine the unreadable sandbox_users.json for diagnostics;
  3. regenerate only the Codex-created sandbox-account passwords and protected blobs;
  4. update the corresponding local sandbox-account passwords;
  5. verify that both new blobs can be decrypted in the context that will later launch the command runner;
  6. surface a precise diagnostic if regeneration fails.

At minimum, the UI should explain that the sandbox credential store is unreadable and offer a scoped repair. App reset/reinstall did not clear this state in the originally reported condition.

Marker creation and validation

The elevated setup helper should ensure that the normal invoking user can read and validate setup_marker.json after setup completes.

Potential safeguards:

  1. explicitly preserve or grant the invoking user SID when creating/replacing the marker;
  2. validate the final marker using the same unelevated identity/context as the desktop runtime;
  3. avoid replacing an inheritable file with one carrying a protected ACL that excludes the caller;
  4. distinguish “file absent,” “invalid schema/version,” and “Access Denied” instead of collapsing all three into “missing or incompatible”;
  5. do not report helper success until the final marker is readable and accepted by the consuming process.

Please consider linking this issue with #30445 and #35407. The matching repair result across multiple users and multiple package generations makes the marker ACL behavior appear product-level rather than machine-specific.

Current status

The sandbox is operational on this machine after:

  1. deliberately regenerating sandbox_users.json; and
  2. restoring access to setup_marker.json.

I am retaining the old credential-store backup, marker backup, saved ACL data, repair transcript, and relevant logs in case engineering wants specific artifacts or a controlled follow-up test.

I do not recommend closing the issue solely because the local installation has recovered. Both recovery steps addressed Codex-owned state that the application did not repair automatically, and the marker ACL defect has independent cross-version reports from other users.

wlhjkl · 20 days ago

I can confirm this failure independently on Codex Desktop for Windows today.

Observed error on every local process launch:

CryptUnprotectData failed: 2148073483
0x8009000B

Additional reproduction evidence from this session:

  • The primary task cannot launch even cmd /c echo tool-ok; failure occurs before process creation.
  • Existing subagents/workers fail at the same boundary.
  • A newly forked same-directory Codex task receives a fresh task id but its normal sandbox still fails identically.
  • apply_patch, shell execution, skill-file reads, and the Node REPL MCP all fail because they ultimately hit the same Windows sandbox credential initialization.
  • Fully terminating all Codex Desktop processes and reopening the app did not recover the credential state.
  • No repository command or project file operation is reached, so this is not a workspace permission or command-content issue.

This has a severe production impact: a long-running engineering task becomes completely unusable, and the only partial escape is requesting non-sandbox execution, which forces additional approval prompts. Recent Desktop updates have added more approval friction while this core Windows sandbox reliability problem remains unresolved. From a user perspective, frequent feature updates are not helpful when basic local execution can be permanently disabled and routine work requires repeated/batch approvals. The experience is extremely frustrating and not suitable for sustained professional development.

Requested fixes:

  1. Add an in-app, auditable “Repair/Recreate Windows sandbox credentials” action that safely regenerates Codex-created sandbox users and DPAPI-protected credentials without requiring OS sign-out or profile deletion.
  2. Detect 0x8009000B explicitly and present a deterministic recovery flow instead of repeatedly retrying every tool call.
  3. Ensure a new/forked task can provision fresh sandbox credentials rather than inheriting the same broken state.
  4. Improve approval ergonomics: allow scoped batch approval for a governed task/workspace, while preserving clear command/path boundaries, instead of requiring repeated prompts for the same recovery workflow.
  5. Preserve task history and local work during repair.

No source code, customer data, device identifiers, or project-specific paths are included in this report.

takon-gi · 16 days ago

I am the reporter of duplicate issue #36052 and can confirm the same failure on another Windows environment.

The issue is still reproducible as of August 12, 2026:

  • Normal sandboxed commands fail before PowerShell starts with:

windows sandbox: CryptUnprotectData failed: 2148073483

  • apply_patch and the browser-control runtime can fail with the same error.
  • In my environment the failure is intermittent rather than permanently continuous. Restarting Codex may temporarily restore normal execution, but the error later returns.
  • Approved/out-of-sandbox execution can sometimes succeed while ordinary sandboxed execution continues to fail.
  • The problem has reproduced across different workspace locations and does not appear related to Japanese file or directory names.

Original duplicate report: #36052

QuentinScDS · 10 days ago

And today