Windows sandbox setup marker ACL prevents Codex from starting sandbox after UAC setup

Open 💬 11 comments Opened Jun 28, 2026 by pekideer

What happened?

After installing/reinstalling Codex for Windows, every normal sandbox command repeatedly triggered UAC and then failed with:

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

The sandbox setup helper itself appeared to complete successfully, but Codex kept treating setup as incomplete:

sandbox setup required: sandbox setup marker missing or incompatible
codex-windows-sandbox-setup.exe] setup binary completed
read-acl-only mode: applying read ACLs
read ACL run completed

The root cause on this machine appears to be the ACL on:

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

The file existed and contained a valid-looking marker, but the normal Codex process could not use it until the current Windows user was explicitly granted access. After granting the current user full control on setup_marker.json, normal sandbox commands started working immediately and no longer triggered UAC.

Environment

Codex Windows package: OpenAI.Codex_26.623.5546.0_x64__2p2nqsd0c76g0
Codex executable path: C:\Program Files\WindowsApps\OpenAI.Codex_26.623.5546.0_x64__2p2nqsd0c76g0\app\resources\codex.exe
PowerShell: 5.1.26100.8737
OS: Windows, build 26100 series

Marker file contents after permission was manually fixed

{
  "version": 5,
  "offline_username": "CodexSandboxOffline",
  "online_username": "CodexSandboxOnline",
  "created_at": "2026-06-28T11:57:37.952492200+00:00",
  "proxy_ports": [],
  "allow_local_binding": false,
  "read_roots": [],
  "write_roots": []
}

Observed behavior

  1. Run a normal command from Codex on Windows.
  2. UAC prompts for codex-windows-sandbox-setup.exe from the Codex WindowsApps package.
  3. User approves UAC.
  4. Setup log says the helper completed.
  5. Codex still fails with orchestrator_helper_incomplete and continues to report setup_marker.json as missing or incompatible.
  6. The cycle repeats on subsequent commands.

Workaround

Granting the current Windows user access to the marker file fixed the issue:

icacls "$env:USERPROFILE\.codex\.sandbox\setup_marker.json" /grant "$env:USERDOMAIN\$env:USERNAME:F"

After that, normal sandbox commands succeeded without additional UAC prompts.

Expected behavior

The Windows sandbox setup helper should create setup_marker.json with ACLs that allow the normal Codex process to read/validate it after UAC-approved setup completes. If the marker exists but is unreadable, Codex should surface a clearer ACL/permission error instead of treating it as missing or incompatible.

View original on GitHub ↗

11 Comments

pekideer · 2 months ago

Additional update: this is not limited to first install/reinstall. The issue reproduced later during setup refresh.

Observed later sequence:

setup refresh: spawning ...\codex-windows-sandbox-setup.exe
setup refresh: processed 4 write roots (read roots delegated); errors=[]
codex-windows-sandbox-setup.exe] setup binary completed
read-acl-only mode: applying read ACLs
read ACL run completed
sandbox setup required: sandbox setup marker missing or incompatible

At that point %USERPROFILE%\.codex\.sandbox\setup_marker.json had just been updated by setup refresh, but attempts to read it failed again with Access is denied.

Reapplying the same workaround restored normal command execution again:

$marker = "$env:USERPROFILE\.codex\.sandbox\setup_marker.json"
takeown /F $marker
icacls $marker /grant "$env:USERDOMAIN\$env:USERNAME:F"

After that, a normal sandbox command succeeded without UAC:

Get-Date -Format o
# succeeded

So the ACL regression appears to recur whenever setup refresh rewrites or updates the marker, not only during initial setup.

folkss · 1 month ago

Confirmed on the current ChatGPT Windows desktop app (formerly Codex Desktop) on 2026-07-10.

I experienced the same behavior:

  • Accepted the UAC prompt for codex-windows-sandbox-setup.exe
  • The app continued to report that Windows sandbox setup was incomplete
  • %USERPROFILE%\.codex\.sandbox\setup_marker.json existed
  • sandbox.log repeatedly showed setup binary completed
  • There was no setup_error.json
  • The marker timestamp matched the latest UAC setup attempt
  • However, the normal Windows user could not read
nunemakerbomba-sudo · 1 month ago

Confirmed with a little more detail on a current build.

Environment:

  • Windows 11 Insider Beta, build 26220
  • ChatGPT Windows app 26.707.37448
  • Codex CLI 0.144.0-alpha.4

In this case the ACL written for %USERPROFILE%\.codex\.sandbox\setup_marker.json contained the machine/domain SID without the current user's RID. Redacted example: the ACE ended in ...3867147518, while the current user SID ended in ...3867147518-1001. icacls therefore displayed a bare machine/domain identity rather than COMPUTER\user.

That matches the observed behavior: the elevated setup process could create/update the marker, but the unelevated Codex process could not read it. Codex then reported both:

sandbox setup required: sandbox setup marker missing or incompatible
windows sandbox: orchestrator_helper_incomplete: setup helper exited successfully before setup completed

All logged OS setup steps (sandbox users, WFP rules, firewall rules, etc.) had succeeded, so this was not caused by the Insider build failing an OS prerequisite.

Granting the real current account access fixed it immediately:

$marker = "$env:USERPROFILE\.codex\.sandbox\setup_marker.json"
$account = "$env:USERDOMAIN\$env:USERNAME"
icacls $marker /grant "${account}:F"

After that, codex sandbox cmd /c "echo SANDBOX_OK" returned SANDBOX_OK, the UAC loop stopped, and normal sandbox commands worked after restarting the app.

The ACL problem can recur when another sandbox setup/refresh path rewrites the marker. In a later attempt, a sandbox-backed helper again failed with orchestrator_helper_incomplete; the marker still existed, but an unelevated Get-Acl failed with UnauthorizedAccessException. So the eventual fix likely needs to preserve/grant the current user's RID on every marker rewrite, not only during initial installation.

nunemakerbomba-sudo · 1 month ago

Follow-up with three additional findings from the same machine, which may help narrow down where the fix needs to go:

1. The truncated-SID ACE is not limited to setup_marker.json.

The parent directory %USERPROFILE%\.codex\.sandbox also carries an explicit (non-inherited) ACE for the bare machine-domain SID — S-1-5-21-<domain> with no user RID appended, which icacls renders as an empty-named MACHINE\ principal:

C:\Users\<user>\.codex\.sandbox  MACHINE\CodexSandboxUsers:(OI)(CI)(M)
                                 NT AUTHORITY\SYSTEM:(OI)(CI)(M)
                                 BUILTIN\Administrators:(OI)(CI)(M)
                                 MACHINE\:(OI)(CI)(RX,W)          <-- bare domain SID, RID missing

Since both the directory and the marker file exhibit the same malformed principal, the bug is likely in a shared "grant the current user" SID-construction helper used by the elevated setup binary, not in the marker-write path specifically. (Possibly relevant: on this machine the computer name is ADMIN and the username is admin, in case the SID/name resolution is name-based somewhere.)

**2. Manual icacls grants get wiped by any entry point re-running setup.**

The Desktop app, the VS Code extension, and the standalone CLI each validate the marker against their own configuration; whichever considers it incompatible re-runs the elevated setup helper, which rewrites the marker with the broken ACL again. In practice the VS Code extension reverted the manual fix that had been applied while repairing the Desktop app about an hour earlier, bringing back the orchestrator_helper_incomplete loop. So the eventual fix indeed needs to apply the correct user ACE on every marker rewrite, as suggested above.

3. Interim mitigation that survives rewrites (for anyone stuck on this until it's fixed):

schtasks /Create /TN CodexMarkerAclFix /SC MINUTE /MO 5 /RU SYSTEM ^
  /TR "icacls C:\Users\<user>\.codex\.sandbox\setup_marker.json /grant <DOMAIN>\<user>:F" /F

A SYSTEM scheduled task re-grants the current user every 5 minutes, so any setup rerun is self-healed without further UAC prompts (worst case: click "Retry Windows setup" once more after ≤5 min). Remove with schtasks /Delete /TN CodexMarkerAclFix /F once a fixed build ships.

Minor correction to the environment listed above: the Windows app version is 26.707.3748.0 (not 26.707.37448).

giostriquer · 1 month ago

I was facing this exact issue, every codex sandbox / desktop-app setup run completes the elevated helper successfully ("setup binary completed", users + firewall + WFP all OK), then codex immediately reports sandbox setup marker missing or incompatible and fails with:

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

When i tried accessing the setup_marker.json i just couldn't which got me thinking that it was probably something weird with my windows setup. While diagnosing it I found that because my machine name was the exact same as my username, the permission was being granted to the machine's domain SID instead of my user's SID.

Essentially: my machine name and my username are both same_user_machine_name. When the setup helper grants the invoking user's marker ACE by account name, LookupAccountName("same_user_machine_name") resolves to the computer/domain object (SidTypeDomain) instead of the local user. Fun confirmation of the trap: running icacls setup_marker.json /grant "same_user_machine_name:R" from an elevated shell also resolves to the domain SID and silently merges into the existing bogus ACE with "success", no change.

Workaround that worked for me

Grant the read ACE by explicit SID, bypassing name resolution (elevated shell; get your SID from whoami /user):

icacls "%USERPROFILE%\.codex\.sandbox\setup_marker.json" /grant "*S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-1001:R"

Immediately after this, codex sandbox -c 'windows.sandbox="elevated"' -- cmd /c whoami runs inside the sandbox as CodexSandboxOffline, exit 0, no UAC. Another potential fix for my case was renaming the PC which i didn't try

Hopefully this helps if anyone encounters a similar issue and it is in this weird setup state as i was.

Environment

  • Windows 11 Pro 10.0.26200, local (Microsoft-account-backed) user
  • codex-cli 0.144.3 (npm), Codex desktop app 26.707.9564.0 (Microsoft Store)
  • Repro'd identically from both the desktop app onboarding and CLI-triggered setup
mericozkaya · 1 month ago

I can confirm this exact issue on a newer Codex Desktop build.

Environment:

  • Microsoft Store package: 26.715.8383.0
  • App-bundled CLI: codex-cli 0.145.0-alpha.27
  • Windows 11 Home Single Language, 10.0.26200.0 x64
  • Locale: tr-TR
  • Local NTFS workspace
  • ChatGPT Plus

The recurring error was:

orchestrator_helper_incomplete: setup helper exited successfully before setup completed

The setup log indicated success:

setup refresh: processed 4 write roots (read roots delegated); errors=[]
setup binary completed

I found some additional ACL evidence.

setup_marker.json existed and was readable from an elevated PowerShell session, but the normal desktop user received Access denied.

The marker DACL did not contain an ACE for the actual desktop user. icacls displayed an unusual trustee similar to:

<COMPUTER_NAME>\:(F)

The redacted SDDL indicated that this trustee used the machine/domain SID prefix without the desktop user's final RID:

(A;;FA;;;S-1-5-21-<MACHINE_SID>)

The actual user SID would be:

S-1-5-21-<MACHINE_SID>-<USER_RID>

Importantly, granting Full Control was not necessary. Granting only read permission on this single file was sufficient:

icacls "C:\Users\<DESKTOP_USER>\.codex\.sandbox\setup_marker.json" /grant "<COMPUTER_NAME>\<DESKTOP_USER>:(R)"

After this change:

  • The setup loop stopped immediately.
  • Sandboxed commands ran as <COMPUTER_NAME>\codexsandboxoffline.
  • Sandboxed file and patch operations worked.
  • workspace-write remained enabled.
  • danger-full-access was not required.

This suggests that the setup helper may be writing an incomplete account-domain SID as the marker-file trustee instead of the full desktop-user SID.

All usernames, computer names, and SID values above are redacted. No authentication or sandbox credential contents are included.

<img width="717" height="60" alt="Image" src="https://github.com/user-attachments/assets/1cac64ba-fea2-4550-bd60-8ac7d0796dc8" />

mericozkaya · 1 month ago

Sharing the Codex prompt that helped me diagnose and repair this

I am sharing this in case it helps someone experiencing the same problem.

I used Codex itself to investigate this issue on my machine. In my case, the elevated sandbox setup had completed and setup_marker.json existed, but the normal Windows user could not read the file because of its ACL. After granting that user read-only access to the single marker file, the setup loop stopped and the workspace-write sandbox began working normally.

This is only a community workaround based on what worked on my machine. It is not official OpenAI guidance, and the same “Windows setup did not finish” message can have other causes.

Environment in which I prepared and tested the prompt:

  • AI model: OpenAI Codex with GPT-5.6 Sol
  • Reasoning effort: Very High (xhigh)
  • Codex Desktop: 26.715.8383.0
  • App-bundled CLI: codex-cli 0.145.0-alpha.27
  • Windows: 10.0.26200.0 x64
  • Locale: tr-TR
  • Subscription: ChatGPT Plus

Other tool-capable Codex models may also be able to perform the diagnosis, but I only tested this workflow with the model and settings listed above.

If your symptoms match this issue, you can try pasting the prompt below into a Codex task. It asks Codex to diagnose the problem without making changes first and to wait for approval before applying the narrowly scoped repair.

If Codex cannot follow these safety constraints, or if it finds a different error, stop rather than allowing it to improvise broad permission changes.

---

Copyable Codex diagnostic and repair prompt

Copy everything inside the block between BEGIN PROMPT and END PROMPT, then paste it into a new Codex task.

BEGIN PROMPT

I am experiencing a repeated Windows sandbox setup loop in Codex Desktop.

Help me determine whether this is caused by an unreadable setup_marker.json file.

Start with read-only diagnostics. Do not modify files, permissions, accounts, or configuration until I explicitly approve a proposed change.

1. Identify the actual desktop user's Codex home directory, normally C:\Users\<DESKTOP_USER>\.codex. Do not assume that a sandbox account's %USERPROFILE% points to the desktop user's profile.

2. Check whether .sandbox\setup_marker.json exists in that Codex home directory.

3. Check relevant lines from .sandbox\sandbox.log and, if present, .sandbox\setup_error.json.

4. Determine whether the setup helper reports successful completion, including messages such as:

   setup binary completed

5. Check whether the normal, non-elevated Windows desktop user can read setup_marker.json. A successful read from an elevated administrator session is not sufficient.

   If you cannot test from the normal host-user context, say so clearly and ask me to run a specific read-only command. Do not infer normal-user access from an administrator or sandbox-account result.

6. Inspect the marker file's ACL and determine whether the actual desktop user's complete SID is present.

7. Check for an unusual ACL trustee containing only the machine/domain SID prefix without the user's final RID.

8. Give me a clear diagnostic summary before proposing any change.

Do not:

- Read or display auth.json
- Read or display .sandbox-secrets
- Read or display sandbox credential contents
- Delete or rename .codex directories
- Delete or recreate Windows accounts
- Modify sandbox-account passwords
- Recursively change permissions
- Use icacls /T
- Grant Full Control for this workaround
- Apply any change before receiving my explicit approval
- Attempt broad ACL resets on the user profile or the entire .codex directory

Only consider the marker-file ACL workaround if all of these conditions are confirmed:

- setup_marker.json exists
- The setup helper completed successfully
- The normal desktop user cannot read the marker
- The actual desktop user is missing from the marker ACL

If all conditions match, propose a command that grants only (R) permission to the actual desktop user on the single setup_marker.json file.

Before running it, show me:

- The exact target file
- The exact Windows principal that will receive access
- The exact proposed command
- Why the command is limited to one file
- What will and will not be changed

Wait for my explicit approval before running the command.

If I approve the change, verify afterward that:

- The normal, non-elevated desktop user can read the marker
- The Windows setup loop no longer appears
- A sandboxed whoami returns a Codex sandbox account
- A simple sandboxed workspace edit succeeds
- sandbox_mode = "workspace-write" remains enabled
- danger-full-access is not required

If the logs instead show SetNamedSecurityInfoW failed: 87, read ACL run had errors, CreateProcessWithLogonW, a missing setup helper, a FAT32 or cloud-mounted workspace problem, or another materially different failure, stop and explain that this workaround may not apply.

Do not attempt a different repair without first explaining the new evidence and asking for my explicit approval.

If you prepare any text for public sharing, redact usernames, computer names, personal profile paths, and complete SID values. Do not redact the exact local target path or Windows principal when showing the proposed command privately to me for approval.

END PROMPT

---

I hope this helps someone avoid the amount of troubleshooting this took on my machine. If the prompt finds a different root cause, please do not apply the marker ACL workaround blindly.

omarc1492 · 1 month ago

Confirmed on Codex Desktop 26.721.3996.0 with Windows 11 build 26200 on a domain-joined computer.

Symptoms:

  • Windows sandbox setup displayed:

codex-windows-sandbox-setup.exe - Application Error
The application was unable to start correctly (0xc0000142)

  • %USERPROFILE%\.codex\.sandbox\setup_marker.json existed.
  • sandbox.log and setup_error.json were not present.
  • The normal desktop account could not read the marker:
Get-Content "$env:USERPROFILE\.codex\.sandbox\setup_marker.json" -Raw
# Access denied
  • icacls from the normal account also returned access denied.

I fixed it from an elevated PowerShell session by granting the actual domain user SID read-only access to the single marker file:

$marker = 'C:\Users\<USER>\.codex\.sandbox\setup_marker.json'
icacls.exe $marker /grant "*<ACTUAL_USER_SID>:(R)"

Afterward:

  • The normal desktop account could read setup_marker.json.
  • Codex stopped reporting incomplete Windows sandbox setup.
  • A direct sandbox test returned the expected sandbox account:
<COMPUTER>\codexsandboxoffline
  • Interactive Codex workspace commands also began running as CodexSandboxOffline.

The marker ACL contained permissions for SYSTEM, Administrators, and another local identity, but not the actual domain desktop account. Granting only (R) on setup_marker.json was sufficient; no recursive ACL changes or Full Control were required.

Usernames, domain names, computer names, and full SID values are redacted.

Thank you @pekideer

JagritGumber · 27 days ago

Claude helped me with this. Confirming this on a different install path, and I think I found the specific cause of the bad ACL.

Environment: @openai/codex v0.146.0 installed via bun add -g, Windows 11 Home Single Language 10.0.26200, Microsoft-Account-linked local admin account. (Different from the reporter's Windows package 26.623.5546.0 / build 26100, so this isn't specific to one installer.)

Why the ACL is wrong

The setup writes the user-facing ACE using the domain SID with the RID stripped off, instead of the account SID.

.sandbox directory SDDL (line breaks added, SIDs partly redacted):

D:AI
(A;OICI;0x1301bf;;;SY)
(A;OICI;0x1301bf;;;BA)
(A;OICI;0x1201bf;;;S-1-5-21-<A>-<B>-<C>)        <-- RID missing
(A;OICI;0x1301bf;;;S-1-5-21-<A>-<B>-<C>-1005)   <-- CodexSandboxUsers

My actual account SID is S-1-5-21-<A>-<B>-<C>-1001. The third ACE stops at the domain portion, so it matches no security principal at all. icacls renders it with an empty account name:

jagri\:(OI)(CI)(RX,W)

and NTAccount.Translate() throws Some or all identity references could not be translated.

setup_marker.json gets the same treatment, with inheritance disabled. Its complete ACL, read as Administrator:

NT AUTHORITY\SYSTEM:(F)
BUILTIN\Administrators:(F)
jagri\:(F)                  <-- RID-stripped SID, intended to be the user

Three ACEs, and the only intended user grant is dead. Under UAC a non-elevated process holds BUILTIN\Administrators as deny-only, so codex.exe matches none of the three and gets a hard access-denied on a file it just wrote as admin. That's why the marker reads as "missing or incompatible" while being present and perfectly well-formed.

So the fix is likely wherever that ACE's SID is constructed - it looks like the RID (last subauthority) is being dropped, leaving the domain SID.

Not stale state

I fully removed Codex first - package, ~\.codex, both CodexSandbox* local accounts, the CodexSandboxUsers group, all codex_sandbox_* firewall rules, and every sandbox ACE across my home directory - then reinstalled clean. The broken ACE was regenerated immediately using the current machine's domain SID.

Self-test for anyone landing here

(Get-Acl "$env:USERPROFILE\.codex\.sandbox\setup_marker.json").Sddl

You're affected if an ACE's SID ends at the domain portion (S-1-5-21-A-B-C) instead of a full account SID (S-1-5-21-A-B-C-<RID>), or if that command fails with access denied as your normal user.

Notes on the workaround

The icacls grant in the original post works. Two refinements:

  • (R) is sufficient - no need for :F. The marker only needs to be readable by the non-elevated process.
  • Granting by SID is more robust than by name, since name-based grants can fail to resolve on some configurations:
$sid = ([Security.Principal.WindowsIdentity]::GetCurrent()).User.Value
icacls "$env:USERPROFILE\.codex\.sandbox\setup_marker.json" /grant "*${sid}:(R)"

Also worth flagging: this comes back after any update that re-runs setup, since the same code path regenerates the broken ACE.

Why retrying is costly

Choosing "try setting up admin sandbox again" isn't free. Each attempt re-applies read ACEs across ~60 paths in the home directory plus write/deny ACEs on project trees, and because those are inheritable (OI)(CI) ACEs, Windows re-stamps every descendant. On one 422k-file project directory here, a single ACL change took several minutes. My sandbox log shows three complete elevated setups in 47 seconds, each with its own UAC prompt.

Lmr159 · 25 days ago

I can confirm this exact setup-marker ACL failure still occurs on a newer Codex Desktop/App-bundled CLI build.

Environment

  • OpenAI.Codex package: 26.727.6591.0
  • Codex CLI: 0.146.0-alpha.9.2
  • Windows 11
  • Local Windows account where the computer name and username collide case-insensitively; exact names and SID values are redacted below

Additional evidence

  • The protected %USERPROFILE%\.codex\.sandbox\setup_marker.json ACL contained an incomplete trustee rendered by icacls as <MACHINE>\:(F).
  • The SID behind that ACE was the local machine/domain SID prefix, without the actual user RID.
  • The real desktop-user SID was the same prefix plus its user RID.
  • The normal, non-elevated Desktop process could not read the marker, even though the elevated setup helper reported successful completion.

A narrowly scoped workaround was sufficient:

  • Grant (R) to the actual desktop-user SID on the single setup_marker.json file.
  • No recursive ACL reset, ownership change, Full Control grant, WindowsApps modification, PC rename, Codex configuration change, or danger-full-access setting was needed.

Post-workaround validation:

  • The repeated setup/UAC loop stopped.
  • A sandboxed whoami.exe returned <MACHINE>\codexsandboxoffline.
  • A native apply_patch regression test passed its complete lifecycle: create, exact byte read-back, update, exact byte read-back, delete, and final absence verification under workspace-write.

This appears to be the same broader unqualified-user problem reported in #27376.

Public main at bb5054f still:

  1. passes bare %USERNAME% as real_user;
  2. resolves it with LookupAccountNameW(NULL, name, ...) without requiring SidTypeUser; and
  3. places the resulting SID into the protected marker DACL.

For a computer-name/username collision, the bare lookup can return the machine/domain SID rather than the user SID. A robust fix would be to capture and pass the initiating user's full SID before elevation—or use an unambiguous qualified identity—and reject a non-user SID result. A regression test should cover a local machine name equal to the username case-insensitively.

Status on my machine: locally mitigated. Upstream status: still unresolved.

Kirill552 · 7 days ago

Reproduced on Windows 10 Pro (build 19045), Codex Store package 26.818.3698.0, bundled CLI 0.148.0-alpha.15. Adding a source-level root cause, because the marker DACL on this machine had a different shape than the bare-domain-SID cases reported above, yet the same end state: the unelevated user cannot open its own setup_marker.json.

Observed state

%USERPROFILE%\.codex\.sandbox\setup_marker.json existed (255 bytes, written by the elevated helper the previous day). From the interactive, unelevated session:

  • Get-Content → Access is denied
  • icacls <marker> → failed outright, i.e. the caller lacked even READ_CONTROL
  • Get-Acl → UnauthorizedAccessException
  • no setup_error.json
  • sandbox.log ended with setup binary completed, WFP setup succeeded ... 12 installed filters, setup refresh: processed 3 write roots (read roots delegated); errors=[]

So the helper launched fine (this is not the os error 5 / 740 helper-launch bug) and every OS-level step succeeded. The parent directory .sandbox did carry an inherited ACE for the interactive user, but that is irrelevant: the marker's own DACL is created protected (D:P), so inheritance is blocked.

After granting only the current user's SID on the marker, icacls listed exactly three ACEs: the freshly added user, NT AUTHORITY\SYSTEM, and BUILTIN\Administrators. No fourth trustee, and no empty-named MACHINE\ principal. Since icacls /grant merges into an existing ACE for the same trustee and never removes ACEs, the pre-existing DACL had to be SYSTEM + Administrators only — meaning the "real user" ACE had collapsed into one of those two.

The app had auto-updated that morning (new %LOCALAPPDATA%\OpenAI\Codex\bin\<hash>\ populated a few minutes before first use), which bumped the CLI and forced marker revalidation — that is why a marker written the day before only became fatal after the update.

Root cause in current main (2151d3a)

The marker ACE is built from an account name, and that name comes from an environment variable with a fallback that silently grants the wrong principal.

codex-rs/windows-sandbox-rs/src/setup.rs — both payload construction sites:

// run_setup_refresh_inner
real_user: std::env::var("USERNAME").unwrap_or_else(|_| "Administrators".to_string()),
// run_elevated_setup_inner
real_user: std::env::var("USERNAME").unwrap_or_else(|_| "Administrators".to_string()),

codex-rs/windows-sandbox-rs/src/bin/setup_main/win/sandbox_users.rs, prepare_setup_marker:

let real_user_sid = resolve_sid(real_user)
    .and_then(|sid| string_from_sid_bytes(&sid).map_err(anyhow::Error::msg))
    ...
let sddl = to_wide(format!(
    "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;{real_user_sid})"
));

Three independent defects feed the same failure:

1. The fallback grants Administrators. If USERNAME is absent from the payload-building process, real_user becomes the literal "Administrators", resolve_sid maps it through well_known_sid_str to S-1-5-32-544, and the SDDL degenerates to D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;BA) — a protected DACL with no ACE for the interactive user at all. An unelevated token holds Administrators as deny-only, so an admin user is locked out just as hard as a standard user. This exactly matches the DACL observed here. A USERNAME of SYSTEM (service/host context) collapses the same way into the SY ACE.

2. resolve_sid ignores SID_NAME_USE. Both copies — winutil.rs::resolve_sid and sandbox_users.rs::resolve_sid — declare let mut use_type: SID_NAME_USE = 0;, pass &mut use_type to LookupAccountNameW, and never read it back. A name that resolves to SidTypeDomain is accepted as if it were a user, yielding a machine/domain SID with no RID. That is the MACHINE\:(F) / machine-name-equals-username case reported earlier in this thread.

3. Identity is name-derived, not token-derived. USERNAME is an inherited, mutable environment variable, not an identity. A DACL is the wrong place to trust it. The crate already has the correct primitive: codex-rs/windows-sandbox-rs/src/token.rs::get_user_sid_bytes does GetTokenInformation(TokenUser) → GetLengthSid → CopySid, which cannot be confused by name collisions, missing env vars, or locale.

4. The failure is then reported as the wrong thing. codex-rs/windows-sandbox-rs/src/identity.rs::load_marker maps every non-NotFound I/O error to None:

Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
Err(err) => { debug_log(...); None }

PermissionDenied is therefore indistinguishable from "no marker", which is why the UI says "sandbox setup marker missing or incompatible" and offers "Retry Windows setup". Retrying re-runs the helper, which rewrites the marker with the same broken DACL — the loop everyone in this thread is stuck in. The one signal that would identify the problem instantly is discarded one line earlier.

Suggested approach

Sketch against 2151d3a, untested (no Rust toolchain on the affected machine — treat as direction, not a patch):

  1. Carry a SID, not a name. Add #[serde(default)] real_user_sid: Option<String> to ElevationPayload, populated on the caller side from the current process token via a safe wrapper over the existing get_user_sid_bytes + string_from_sid_bytes. In prepare_setup_marker, prefer that SID.
  2. Delete the Administrators fallback. If the caller's identity cannot be determined, return SetupErrorCode::HelperSetupMarkerWriteFailed instead of writing a marker nobody can read. Failing loudly is strictly better than a protected DACL that excludes the only principal that needs it.
  3. Validate SID_NAME_USE wherever a name still has to be resolved: require SidTypeUser for the real user and reject SidTypeDomain / SidTypeInvalid / SidTypeUnknown with a distinct error. Both copies of resolve_sid need it; deduplicating them would also help.
  4. Re-apply the user ACE on every marker rewrite, not just on first install. As noted above in this thread, the Desktop app, the VS Code extension, and the standalone CLI each rewrite the marker, so a manual icacls grant survives only until the next entry point runs setup.
  5. Surface PermissionDenied distinctly in load_marker, and do not offer "Retry Windows setup" for it — retrying cannot fix an ACL the helper itself just wrote. An error naming the marker path and the denied access would have made this a one-minute diagnosis instead of a thread.

Workaround confirmation

Granting by explicit SID (name resolution avoided, per the earlier comment in this thread) fixed it immediately, elevated:

takeown /F "%USERPROFILE%\.codex\.sandbox\setup_marker.json"
icacls "%USERPROFILE%\.codex\.sandbox\setup_marker.json" /grant "*S-1-5-21-<redacted>-<RID>:(F)"

Verification after the grant, unelevated, no UAC prompt:

> codex.exe sandbox -- cmd /c "echo SANDBOX_OK && whoami"
SANDBOX_OK
<machine>\codexsandboxoffline

Marker readable, "version": 5, sandboxed process running as the offline sandbox user, exit 0.