Codex desktop app on Windows injects split writable roots, causing `apply_patch` to fail before patching workspace files, forcing agents to fallback to bypass the sandbox and write files using powershell

Open 💬 9 comments Opened Jun 30, 2026 by PurpleDevX
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

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

26.623.70822

What subscription do you have?

Pro

What platform is your computer?

Microsoft Windows NT 10.0.26100.0 x64

What issue are you seeing?

The safe edit path (apply_patch) is unusable in Codex desktop app sessions on Windows. Agents have to fall back to shell-based file rewrites inside the project, which bypasses the sandbox and is less precise and more error-prone.

The apply_patch tool call fails when patching files inside the active workspace root. The failure happens before the target file is read or modified.

Observed Error (according to agent)

apply_patch verification failed: Failed to read file to update C:\git\foobar\apps\server\src\routes\sync.ts:
failed to prepare fs sandbox:
failed to prepare windows sandbox wrapper:
windows unelevated restricted-token sandbox cannot enforce split writable root sets directly;
refusing to run unsandboxed

Observed Behavior
The desktop app provides a managed sandbox profile with multiple writable roots (C:\git\foobar and C:\tmp). On Windows, apply_patch cannot construct/enforce that split-root sandbox using the unelevated restricted-token backend, so it refuses to run at all.

What steps can reproduce the bug?

  1. Ensure workspace-write sandbox mode is enabled.
  2. Create a new session in C:\git\foobar.
  3. Send prompt Create a test.txt file that says "hello world"
  4. Observe the file is created.
  5. Send prompt List the workspace roots added to this session, and also list all writable paths
  6. Observe the only workspace root is C:\git\foobar and writable paths are C:\git\foobar, C:\tmp, :tmpdir
  7. Send prompt Use the apply_patch tool to change "hello" in test.txt to "bye"
  8. Observe agent responds with I first tried apply_patch, but it failed because the Windows sandbox wrapper refused to run it in this restricted writable-root setup, so I made the same edit with PowerShell.

What is the expected behavior?

apply_patch should work for files inside the active writable workspace root, or the desktop app should not start Windows sessions with a sandbox shape that makes apply_patch unusable.

Additional information

The safe edit path (apply_patch) is unusable in Codex desktop app sessions on Windows. Agents have to fall back to shell-based file rewrites inside the project, which bypasses the sandbox and is less precise and more error-prone.

View original on GitHub ↗

9 Comments

github-actions[bot] contributor · 20 days ago

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

  • #30009

Powered by Codex Action

TheCrake · 20 days ago

Yeah, I'm still having this issue as of today. I've confirmed the issue is not present in the current IDE version of codex, only the windows app. I also checked older chat logs from a few weeks ago in codex and they were not having this issue, they were able to use apply_patch without errors.

cyhdzh · 19 days ago

I've got the same issue here when I use the codex VSCode extension.

peancor · 18 days ago

Adding some diagnostics from my Windows setup.

Environment:

  • Windows reports: Windows 10 Pro, 25H2, build 26200.8655, 64-bit.
  • PowerShell: 7.6.3.
  • Codex Desktop package: 26.623.11225.0, Status: Ok.
  • Internal Codex Desktop runtime: codex-cli 0.142.5.

What I tried:

  • Reinstalled Codex Desktop from Settings.
  • Restarted Codex.
  • Deleted Codex temporary state.
  • Tested across multiple repositories/workspaces.
  • Tried both Windows sandbox modes: unelevated and elevated.
  • Tried sandbox_private_desktop = false.
  • Tried excluding tmp roots with exclude_tmpdir_env_var = true and exclude_slash_tmp = true.

Observed behavior:

  • With sandbox = "unelevated":
  • Normal shell commands work.
  • apply_patch add works.
  • apply_patch update/delete fails with:

windows unelevated restricted-token sandbox cannot enforce split writable root sets directly; refusing to run unsandboxed

  • With sandbox = "elevated":
  • apply_patch add/update/delete works.
  • Normal shell commands fail before starting with:

CreateProcessAsUserW failed: 5

  • Setting sandbox_private_desktop = false did not change this.
my-short-circuits · 10 days ago

Wasted a bunch of tokens trying to get Sol to fix this until I found my way here. Please fix this..

rjgc80-cyber · 9 days ago

I can independently reproduce this in Codex Desktop on native Windows.

Configuration:

approval_policy = "on-request"
sandbox_mode = "workspace-write"

[windows]
sandbox = "unelevated"

[sandbox_workspace_write]
writable_roots = ["<workspace>"]

The Desktop UI showed a single workspace root, but the managed permission profile still injected other writable locations, including temporary/runtime paths and paths previously available to the task.

Minimal test:

*** Begin Patch
*** Add File: .codex-apply-patch-test.tmp
+apply_patch OK
*** End Patch

In one session, the patch failed before creation with:

apply_patch verification failed: Failed to read <workspace>\\.codex-apply-patch-test.tmp:
failed to prepare fs sandbox:
failed to prepare windows sandbox wrapper:
windows unelevated restricted-token sandbox cannot enforce split writable root sets directly;
refusing to run unsandboxed

Troubleshooting performed:

  • Reduced the visible workspace to one root.
  • Configured only one explicit writable_roots entry.
  • Restarted Codex.
  • Tested Codex launched normally and with "Run as administrator".
  • Running the packaged app as administrator did not change the internal restricted-token behavior.

A separate fresh-session test exhibited a closely related failure: the Add File patch succeeded, but deleting the same file through apply_patch failed with windows_sandbox_helper_unknown_error. The file could then be removed through another filesystem operation. This second symptom appears to match #31229.

The filename and patch body are ASCII-only and minimal. The failures occur during Windows sandbox preparation/ACL handling, before normal patch processing. This also encourages fallback to shell-based writes, bypassing the normal patch review workflow.

jkenter0528 · 7 days ago

I can independently reproduce this on Codex Desktop for Windows with the unelevated sandbox.

Environment:

  • Recent Codex Desktop build and bundled/standalone Codex CLI
  • Windows 11
  • Local workspace path redacted
  • No custom permission profile or user-configured writable roots
  • [windows] sandbox = "unelevated"

Repro:

  1. In a fresh Desktop task, built-in apply_patch Add File inside the workspace succeeds.
  2. Five consecutive built-in apply_patch Update File attempts against that existing file fail: 0/5.
  3. Built-in apply_patch Delete File fails with the same error.
  4. Ordinary sandboxed PowerShell works.
  5. Desktop displays a workspace root, normal temp root, and a per-task internal visualization root.

Exact error:

windows unelevated restricted-token sandbox cannot enforce split writable root sets directly; refusing to run unsandboxed

I also tested the standalone Codex CLI directly in workspace-write mode, without Desktop’s visualization root. Its effective writable roots were only:

<workspace>
<temporary directory>

Add File still succeeded, but the first existing-file Update failed with the identical error. This shows the visualization root is not necessary to trigger the issue; the normal workspace-plus-temp root set is sufficient.

I removed legacy custom workspace/skill/plugin roots and fully restarted Desktop. I also disabled the Visualize plugin. Neither changed the failure. This is therefore not caused by user-configured roots, stale skill roots, the temporary arg0 launcher, or Visualize alone.

Security concern: in Desktop, harmless Add File probes outside the displayed writable roots were unexpectedly created, while existing-file Update/Delete fail closed. That leaves apply_patch both unreliable and inconsistent with the declared boundary.

This appears to require a Codex Windows runtime fix. The unelevated restricted-token backend should support the effective split writable-root set, or the runtime should normalize/project its internal and temporary roots consistently before apply_patch is invoked. A local config workaround that removes normal temp access or broadens filesystem access would not be an acceptable solution.

PurpleDevX · 6 days ago

@fcoury-oai Heads up that your merged Codex PR #31138 which was intended to fix this either didn't get merged into the new unified ChatGPT app, or it didn't resolve the issue.

This bug still persists, and 5.6 wastes even more time on working around it constantly (I frequently see the thinking text say Planning a workaround for the sandbox apply_patch issue).

There is now also an additional even worse case which is blocking development of one of my projects completely. After extended development, some corner-case issue has been hit, where apply_patch cannot be used and agents refuse to work around it even in new sessions. I'm assuming this is due to the new ChatGPT app having a stricter system prompt. Agents simply say Blocked by the Codex patch helper: every apply_patch invocation fails because the WindowsApps executable returns “Access is denied,” including approved out-of-sandbox execution. No matter how much I've tried to get agents to bypass the sandbox restriction and use powershell for this project, they insist that their system prompt strictly prohibits bypassing the sandbox.

ameenah-syed · 4 days ago

Additional source-level evidence from codex-cli 0.143.0 and the current public main branch.

Observed source boundary

I reproduced the exact pre-file-access failure:

failed to prepare fs sandbox:
failed to prepare windows sandbox wrapper:
windows unelevated restricted-token sandbox cannot enforce split writable root sets directly;
refusing to run unsandboxed

The installed 0.143.0 binary maps to tag rust-v0.143.0, commit c4d748f586a84a3ed5b6aceb82e9a1db4abb1cda. The same refusal was still present when checked on public main at 78ba047bdae3db0342dee11d8d9ef5582fe8ce49.

The fail-closed check is in codex-rs/sandboxing/src/windows.rs, function resolve_windows_restricted_token_filesystem_overrides. It compares the compatibility projection writable roots with the requested split-policy roots and returns this diagnostic whenever the sets differ.

The lower Windows sandbox already has much of the required representation:

  • WindowsSandboxFilesystemOverrides.write_roots_override
  • wrapper support for --write-roots-json
  • one path-scoped capability SID per writable root in root_capability_sids
  • WRITE_RESTRICTED token creation with multiple restricting SIDs

However, the unelevated unified-exec branch does not forward WindowsSandboxSessionRequest.write_roots_override into spawn_windows_sandbox_session_legacy. The capture path in codex-rs/core/src/exec.rs similarly forwards the override only to the elevated backend.

Two related fail-closed/atomicity gaps are relevant to a complete fix:

  • canonical_existing in codex-rs/windows-sandbox-rs/src/setup.rs silently removes nonexistent roots.
  • apply_legacy_session_acl_rules in spawn_prep.rs suppresses several allow/deny ACL errors, and the setup helper logs missing write roots as skipped.

Reproduction detail

A named Add File probe succeeded once in the isolated official-source checkout. The immediately following built-in apply_patch Delete File operation failed during sandbox preparation with the split-root diagnostic, before reading the probe. Shell and Git access continuing to work does not disprove this because those operations use a different launch path.

Proposed enforcement contract

A complete launcher/policy fix should:

  1. Canonicalize and deduplicate the complete writable-root collection using Windows path semantics, including aliases, case, separators, UNC, and reparse points.
  2. Preserve every distinct root without widening access to a common ancestor or drive.
  3. Validate all roots and prepare all grants before child creation.
  4. Roll back partial ACL changes if any validation or grant fails.
  5. Preserve zero-root and single-root behavior.
  6. Never fall back to unrestricted execution, the first root only, or silently discarded roots.
  7. Keep undeclared parents, siblings, junction targets, and unrelated drives inaccessible.
  8. Produce a structured launch error naming the failed phase/root.

Windows CI should cover same-drive and cross-drive roots, spaces and Unicode, UNC, junction/reparse containment, alias deduplication, invalid-root partial failure and cleanup, shell plus built-in apply_patch writes in every declared root, and outside-root denial.

This is a root-cause analysis and proposed acceptance contract, not a claim that the platform fix has been implemented or validated.