Codex Desktop on Windows: `.git/FETCH_HEAD: Permission denied` from sandbox-induced orphan-SID Deny ACEs

Resolved 💬 6 comments Opened May 6, 2026 by PsyDocH1801 Closed May 6, 2026
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Environment

  • Codex Desktop: 26.429.3425.0 (x64, Microsoft Store / WindowsApps install)
  • OS: Windows 11 Pro 26200
  • Repo: fresh git clone of a public GitHub repo into C:\Repos\<repo>\ (path outside any OneDrive scope)
  • Account: standard local user, not Administrator
  • Codex CLI 0.128.0 also installed on the same machine; not used for this reproduction

Summary

git pull --ff-only from inside Codex Desktop fails with error: cannot open '.git/FETCH_HEAD': Permission denied. From a normal PowerShell session as the same user against the same path, git pull --ff-only succeeds.

After Codex Desktop's first contact with the repo, host-side Get-Acl .git shows two new explicit Deny ACEs against an "orphan" SID — orphan from the host's IdentityNotMappedException POV but evidently resolving inside the Codex Desktop sandbox to the sandbox's effective principal, since that's the only thing that explains why Codex's own writes inside .git are blocked while host writes succeed.

Reproduction

  1. Fresh git clone into a path outside any OneDrive Known Folder Move scope. Confirm the freshly-cloned .git carries zero explicit Deny ACEs and no orphan SIDs (icacls <repo>\.git should show only inherited BUILTIN\Administrators (F), NT AUTHORITY\SYSTEM (F), BUILTIN\Users (RX), NT AUTHORITY\Authenticated Users (M)).
  2. Open a fresh Codex Desktop session pointed at the clone.
  3. Have Codex run git pull --ff-only.
  4. Observe the failure inside Codex: error: cannot open '.git/FETCH_HEAD': Permission denied.
  5. Re-run icacls <repo>\.git from a normal host PowerShell session. Two new explicit Deny ACEs are present:

``
<orphan-SID>:(DENY)(W,D,Rc,DC)
<orphan-SID>:(OI)(CI)(IO)(DENY)(W,D,Rc,GW,DC)
``

The (OI)(CI)(IO) ACE propagates onto every newly-created child of .git, which is what blocks FETCH_HEAD write on the next pull attempt.

Mechanism (hypothesis)

The "orphan" SID has the same shape as a normal machine SID (S-1-5-21-<machine>-<RID>) but its machine prefix matches no SID issuer registered with this Windows host's LSA, so IdentityReference.Translate([NTAccount]) throws IdentityNotMappedException. From the host's POV the Deny is a no-op — that matches the observation that host PowerShell Git operations succeed through these ACEs.

From the Codex Desktop sandbox's POV, however, the same SID resolves to the sandbox's effective principal — otherwise the Deny would be a no-op there too. So Codex Desktop is locking itself out of .git on every clone it touches.

Confirming side-observation: on first contact with a workspace root, Codex Desktop adds two Allow ACEs at the workspace root level — one for the documented CodexSandboxUsers group (expected), and one for a different orphan SID. The Allow case is harmless (Allow for an unmappable SID is a no-op from host POV). The Deny case is the Git breakage.

This appears to be the Windows-native-sandbox manifestation of the same design pattern documented for the Linux bubblewrap path in #14338 (.git/FETCH_HEAD: Read-only file system because bubblewrap mounts .git read-only after writable roots are applied) and reported on the VS Code extension surface in #9341 (.git/index.lock: Permission denied from the same Windows sandbox layer).

Suggested triage

A writable-gitdir opt-in along the lines requested in #14338 would address the underlying design constraint cross-platform.

In the meantime, the Windows sandbox lockout produces a generic "Permission denied" with no in-sandbox indication that the Codex sandbox is the cause. #9341 covered that visibility ask for the VS Code extension surface; the same applies to Codex Desktop standalone. A persistent, in-app indicator that the experimental Windows sandbox is active and that Git operations against .git inside the workspace will fail would prevent users from spending hours diagnosing this as a OneDrive / antivirus / NTFS ownership issue (which is exactly the path that led to filing this report).

Workaround

#9341's reporter confirmed that experimental_windows_sandbox = false in ~/.codex/config.toml resolved their .git/index.lock failure. We have not yet tested this against the FETCH_HEAD reproduction locally; planning to test on a disposable clone next and will follow up here.

Operational workaround in use: never let Codex Desktop run Git operations on this repo. Host PowerShell as the standard user runs all Git; Codex Desktop is restricted to non-Git file edits. That works because the orphan-SID Deny ACEs are no-ops from host POV.

Related issues

  • #9341 — VS Code extension surface, .git/index.lock failure, same Windows sandbox cause
  • #14338 — Linux bubblewrap surface, same .git/FETCH_HEAD symptom, request for writable-gitdir opt-in
  • #12343 — sandbox creates CodexSandbox* groups; can leave stale SIDs after uninstall
  • #13378 — sandbox ACL setup leaves persistent permission pollution
  • #15310 — desktop automations falling back to workspace-write sandbox regardless of config

View original on GitHub ↗

6 Comments

github-actions[bot] contributor · 3 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #19786

Powered by Codex Action

PsyDocH1801 · 3 months ago

Follow-up after testing on a disposable clone outside any OneDrive scope (C:\acl-test\Git-Obsidian-backup).

TL;DR

  • The workaround cited in #9341 ([features].experimental_windows_sandbox = false) is no longer functional. codex features list in CLI 0.128.0 reports both experimental_windows_sandbox and elevated_windows_sandbox as removed. Setting them in [features] is a no-op.
  • The current sandbox knob is [windows].sandbox, which accepts only elevated (default) or unelevated — there is no off/disabled/none value. Setting any other value fails at config-load: unknown variant '<value>', expected 'elevated' or 'unelevated'.
  • Both Codex Desktop modes (elevated, unelevated) and Codex CLI in workspace-write mode all reproduce error: cannot open '.git/FETCH_HEAD': Permission denied on a fresh clone outside OneDrive scope. The sandbox layer is the cause — not Git, not NTFS, not the repo, not any environmental factor.
  • Control: codex exec --dangerously-bypass-approvals-and-sandbox -C <clone> "git pull --ff-only" succeeds with exit 0. That is the cleanest possible isolation of the sandbox as the operative factor.
  • The ACL-pollution side-effect splits across modes:
  • Codex Desktop elevated: writes orphan-SID Deny ACEs on .git. Yes (host-visible).
  • Codex Desktop unelevated: same FETCH_HEAD failure, but no Deny ACEs written. The unelevated mode enforces via restricted-token semantics, not via DACL changes.
  • Codex CLI workspace-write: writes orphan-SID Deny ACEs (with a fresh per-session orphan SID, different from the Desktop one).

Detail

Test environment

Same as the original report: Codex Desktop 26.429.3425.0 (x64, Microsoft Store / WindowsApps install) + Codex CLI 0.128.0, Windows 11 Pro 26200, standard local user. Disposable clone outside OneDrive scope so any orphan-SID ACE that appears is causally attributable to Codex.

Test 1 — [windows] sandbox = "unelevated"

Procedure: edit ~/.codex/config.toml to set [windows] sandbox = "unelevated", fully exit Codex Desktop (kill all Codex processes), relaunch Codex Desktop, point at the disposable clone, run git pull --ff-only from inside Codex.

Result: identical error: cannot open '.git/FETCH_HEAD': Permission denied failure as the elevated mode. But host-side Get-Acl .git showed zero new explicit Deny ACEs — the DACL was byte-identical to the clean-baseline state from immediately after git clone.

Implication: the unelevated variant of the Windows restricted-token sandbox is "cleaner" in that it doesn't pollute host-visible ACLs, but it doesn't fix the underlying lockout. Whatever mechanism in unelevated mode prevents the sandbox from writing inside .git is independent of the DACL.

Test 2 — Codex CLI workspace-write

Procedure (from a host PowerShell session, with toml restored to elevated):

codex exec -s workspace-write -C C:\acl-test\Git-Obsidian-backup `
    "Run the shell command: git pull --ff-only. Then report exactly: (1) the command exit code, (2) any stdout, (3) any stderr."

Result: same error: cannot open '.git/FETCH_HEAD': Permission denied from inside the sandbox.

Post-test icacls C:\acl-test\Git-Obsidian-backup\.git:

S-1-5-21-1055846344-1817993210-866058223-1263234699:(DENY)(W,D,Rc,DC)
S-1-5-21-1055846344-1817993210-866058223-1263234699:(OI)(CI)(IO)(DENY)(W,D,Rc,GW,DC)
S-1-5-21-1055846344-1817993210-866058223-1263234699:(I)(OI)(CI)(M,DC)

Two explicit Denies + one inherited Allow against S-1-5-21-1055846344-1817993210-866058223-1263234699. From the host's POV this SID is orphan (Translate([NTAccount]) throws IdentityNotMappedException); its prefix matches no SID issuer registered with this Windows host's LSA. Same shape as the original report (S-1-5-21-3824534274-3844480456-2110850372-3580790307 from the original Codex Desktop pull): one direct Deny + one (OI)(CI)(IO) inherit-only Deny that propagates onto every newly-created child of .git.

This is the fourth distinct orphan SID family observed across testing (live repo, two disposable-clone sessions, plus a workspace-root Allow side-finding). The orphan SID is per-Codex-session, not per-machine.

Test 3 — control with --dangerously-bypass-approvals-and-sandbox

codex exec --dangerously-bypass-approvals-and-sandbox -C C:\acl-test\Git-Obsidian-backup `
    "Run: git pull --ff-only. Report exit code and stdout/stderr."

Result: exit 0, fast-forwarded cleanly. Sandbox unambiguously the cause.

Updated mechanism summary

  1. The FETCH_HEAD lockout is universal across all sandboxed Codex modes (Desktop elevated, Desktop unelevated, CLI workspace-write tested; CLI read-only would presumably be the same). The only path that lets git pull --ff-only succeed is sandbox-bypass — exposed on the CLI as --dangerously-bypass-approvals-and-sandbox, not exposed as a config option in Codex Desktop.
  2. The orphan-SID Deny ACE pollution is a side-effect of two specific modes: Desktop elevated and CLI workspace-write. Desktop unelevated reproduces the lockout without writing Denies.
  3. The orphan SID is per-session, not per-machine. Four distinct orphan SIDs observed across testing.
  4. From inside the sandbox the SID resolves to the sandbox's effective principal, otherwise the Deny would be a no-op there too. The host's Translate cannot see this principal because it lives in Codex's sandbox identity layer.

What this implies for the original report

The original report's "Workaround" section cited the experimental_windows_sandbox toggle pending local test. That section is now stale — the toggle no longer exists in CLI 0.128.0. There is currently no in-product way to disable the sandbox in Codex Desktop; the only working bypass is via Codex CLI's --dangerously-bypass-approvals-and-sandbox, which is not a comparable durable workflow (it disables the sandbox entirely for that exec, with all the safety implications that come with it).

The writable-gitdir opt-in proposed in #14338 for the Linux bubblewrap path remains the cleanest cross-platform fix.

In the meantime, the Codex Desktop unelevated variant is at least an improvement on elevated for the host-ACL-pollution dimension: same lockout, but no accumulating Deny ACEs that need a RemoveAccessRuleSpecific cleanup recipe to remove. If elevated cannot be deprecated entirely, surfacing unelevated as the recommended default would reduce surprise for users who don't realise their .git directories are accumulating orphan-SID Deny ACEs every Codex session.

PsyDocH1801 · 3 months ago

Correction and closure.

After the follow-up testing, I learned that Codex Desktop has an in-app "Full Access" toggle under settings that maps to sandbox_mode = "danger-full-access" + approval_policy = "never" — exactly the configuration that allows git pull --ff-only to succeed from inside Codex Desktop. The toggle is on by default in some installs (mine on the old laptop) and off in others (mine on the new laptop), which fully explains the asymmetry described in the original report.

The original report's framing was therefore wrong on its central claim ("no in-product way to disable the sandbox in Codex Desktop"). The toggle exists. This is a settings-discovery issue on my end, not a bug in Codex.

Two sub-concerns surfaced during testing that may still be worth tracking — but better as separate, focused issues than as a reframe of this one:

  1. Discoverability. The in-sandbox error: cannot open '.git/FETCH_HEAD': Permission denied is a generic OS error with no Codex-side hint that the sandbox is the cause or that Full Access in settings would resolve it. I spent hours chasing OneDrive ACL theories before the sandbox layer became visible. A more specific in-app error or a one-line "this command was blocked by the sandbox; see settings → Full Access" would prevent the same chase for the next user.
  1. ACL hygiene in elevated mode. Even when users keep Default Permissions (sandbox on), [windows] sandbox = "elevated" writes orphan-SID Deny ACEs on .git per session. From the host POV the SIDs don't translate (IdentityNotMappedException), so the ACEs are no-ops and don't break host Git, but they accumulate permanently in the NTFS DACL across sessions. [windows] sandbox = "unelevated" reproduces the same lockout from inside the sandbox without writing the Denies, so the pollution is specific to elevated mode rather than the sandbox layer in general. Worth noting if you're tracking sandbox-cleanup hygiene.

Neither rises to the level of the original framing. Closing this; happy to file the sub-concerns separately if either is of interest, otherwise the writable-gitdir cross-platform request in #14338 covers the underlying ergonomic ask.

Apologies for the noise.

PsyDocH1801 · 3 months ago

Closing per the correction comment above — original framing was wrong on its central claim. The Full Access toggle in Codex Desktop settings is the in-product disable I claimed didn't exist.

xsmilebook · 2 months ago

Possible Fix for Codex Git Permission Errors on Windows

I also encountered this issue while using Codex in workspace-write mode. In my case, the repository root was writable, so Codex could still edit normal code and document files, but Git operations failed because Git needed to write metadata inside the .git directory.

The issue was not caused by Git itself, the repository contents, or the workspace root permissions. The problem was caused by abnormal Windows ACL entries on the .git directory.

The key point is that two repositories may appear similar at the workspace level, but their actual .git ACLs can be different. A repository root can be writable, while Git operations still fail because Git needs to create or update files such as .git\index.lock or .git\FETCH_HEAD.

In the problematic repository, .git and .git\index contained additional explicit Deny ACEs. Since explicit Deny entries take precedence over Allow entries in Windows ACLs, Git could not create .git\index.lock, even though the repository root itself was writable.

A possible fix is to reset the ACL of the .git directory and re-enable inheritance from the repository root. This should be run from a normal PowerShell session:

```powershell id="79dxaq"
cd <path-to-your-repository>
icacls .git /reset /T /C
icacls .git /inheritance:e /T /C


After resetting the `.git` ACL and restoring inheritance, Git should be able to create `.git\index.lock` again, and the permission error may be resolved.

This fix is specifically for cases where normal files in the workspace are editable, but Git operations fail with errors related to `.git\index.lock`, `.git\FETCH_HEAD`, or other Git metadata files. It is worth checking the actual ACLs of `.git` before assuming that the whole workspace has the same permissions.
iragis · 18 days ago

I ran into a related failure from the same subsystem that may be worth cross-referencing here.

Besides the Deny ACEs on .git, the sandbox can also rewrite ownership of project directories to CodexSandboxOffline — a transient identity that stops resolving afterwards, which then blocks Codex's own attempts to repair the ACLs. Symptoms look different (SetNamedSecurityInfoW failed: 5, CreateProcessWithLogonW failed: 1056) but the trigger is the same: a sandbox operation interrupted partway through.

What reportedly fixed it permanently, from an elevated PowerShell with Codex closed:

takeown /F "<PROJECT_ROOT>" /R /D Y
icacls "<PROJECT_ROOT>" /setowner "<MACHINE>\<USER>" /T /C
icacls "<PROJECT_ROOT>" /inheritance:e /T /C
Worth checking whether you're also affected: icacls "<PROJECT_ROOT>" /T /C | Select-String "CodexSandbox"

I've been collecting the variants of this and what does/doesn't work here: https://bugswiki.com/troubleshooting/codex-couldnt-set-up-sandbox/ — the experimental_windows_sandbox = false workaround from this thread is in there too.