Custom Permissions Rewritten to Read-Only in Windows OS App

Resolved 💬 2 comments Opened Jun 17, 2026 by rwludwig Closed Jun 21, 2026

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

OpenAI.Codex_26.611.8604.0_x64

What subscription do you have?

Enterprise API Key

What platform is your computer?

Microsoft Windows NT 10.0.26200.0 x64

What issue are you seeing?

Summary

Codex Desktop appears to overwrite a custom permission configuration from workspaceWrite to readOnly when a prompt is submitted in an existing local thread.

The issue reproduces after updating to:

OpenAI.Codex_26.611.8604.0_x64

The runtime config parser accepts the configured permission profile, and the thread permission entry can exist as workspaceWrite after app restart/update. However, submitting a prompt rewrites the same thread's persisted permission entry to readOnly. The sandbox runner then receives zero write roots and correctly applies read-only ACLs.

Environment

Codex Desktop package:
OpenAI.Codex_26.611.8604.0_x64

Codex executable path:
C:\Program Files\WindowsApps\OpenAI.Codex_26.611.8604.0_x64__2p2nqsd0c76g0\app\resources\codex.exe

OS:
Windows 11 Professional, 10.0.26200

Thread ID:
019ed65c-61e7-7290-bb5f-290caf86909d

Global state file:
C:\Users\User\.codex\.codex-global-state.json

Config

The global config includes a custom permission profile intended to allow workspace writes by default:

default_permissions = "trusted_workspace_edit"

[allowed_permission_profiles]
":read-only" = true
":workspace" = true
"trusted_workspace_edit" = true

[permissions.trusted_workspace_edit]
extends = ":workspace"

[permissions.trusted_workspace_edit.filesystem.":workspace_roots"]
"." = "write"
".git" = "write"
".agents" = "read"
".codex" = "read"
"**/.env" = "deny"
"**/.env.*" = "deny"
"**/*.env" = "deny"

[permissions.trusted_workspace_edit.network]
enabled = true
allow_local_binding = true

codex doctor --json reported that config.toml parsed successfully:

config.toml parse: ok
CODEX_HOME: C:\Users\User\.codex
filesystem sandbox: restricted
network sandbox: enabled

What steps can reproduce the bug?

Reproduction

  1. Use custom config mode in Codex Desktop.
  2. Confirm that the persisted thread permission entry is workspaceWrite after app update/restart.
  3. Send a prompt in the same thread.
  4. Re-check:
C:\Users\User\.codex\.codex-global-state.json

Key:

electron-persisted-atom-state.heartbeat-thread-permissions-by-id.<threadId>

What is the expected behavior?

Expected Result

The thread permission should remain workspace-write, matching the active custom permission profile:

{
  "sandboxPolicy": {
    "type": "workspaceWrite"
  }
}

Actual Result

Immediately after submitting a prompt, the same thread permission entry is rewritten to:

{
  "approvalPolicy": "on-request",
  "approvalsReviewer": "auto_review",
  "sandboxPolicy": {
    "type": "readOnly",
    "networkAccess": false
  }
}

Additional information

The app state also shows:

{
  "agentMode": "custom",
  "preferredNonFullAccessMode": null
}

Sandbox Log Evidence

After the prompt-time rewrite, the sandbox setup receives zero write roots:

setup refresh: spawning C:\Program Files\WindowsApps\OpenAI.Codex_26.611.8604.0_x64__2p2nqsd0c76g0\app\resources\codex-windows-sandbox-setup.exe
setup refresh: processed 0 write roots (read roots delegated); errors=[]
read-acl-only mode: applying read ACLs

This indicates the sandbox runner is obeying the persisted read-only policy it was given. The likely failure is upstream, in the prompt/send permission writeback path.

Static Analysis Findings

Static inspection of the packaged Desktop webview bundle suggests the prompt-time custom permission path is still using the older flat config schema.

Relevant packaged files:

C:\Program Files\WindowsApps\OpenAI.Codex_26.611.8604.0_x64__2p2nqsd0c76g0\app\resources\app.asar

Relevant bundled modules:

/webview/assets/src-DEDxOnN6.js
/webview/assets/use-permissions-mode-9OJM2a7p.js
/webview/assets/build-start-conversation-params-BWnyzAKG.js
/webview/assets/config-queries-BAeIrVPL.js
/webview/assets/agent-settings-DVuPmCWg.js

In /webview/assets/src-DEDxOnN6.js, minified function Xf maps an agent/permission mode to a concrete permission object:

function Xf(e,t,n){
  switch(e){
    case `read-only`: return qf();
    case `full-access`: return Jf();
    case `auto`: return Kf(t);
    case `granular`: return Kf(t,void 0,Nf);
    case `guardian-approvals`: ...
    case `custom`: return Yf(t,n)
  }
}

For custom, it delegates to Yf. That function appears to inspect only the legacy flat config fields:

sandbox_mode
approval_policy
sandbox_workspace_write
approvals_reviewer

If sandbox_mode is missing, null, or undefined, Yf falls back to qf(...), which produces:

{
  sandboxPolicy: {
    type: `readOnly`,
    networkAccess: false
  }
}

In /webview/assets/use-permissions-mode-9OJM2a7p.js, the prompt-time writeback path calls the same permission resolver and persists the result with:

update-thread-settings-for-next-turn

That matches the observed behavior: the custom profile is initially present as workspaceWrite, but on prompt submission the webview computes and writes a readOnly policy.

An ASAR-aware scan of shipped webview JS found references to:

sandbox_mode
approval_policy
sandbox_workspace_write
approvals_reviewer

but did not find references to:

default_permissions
allowed_permission_profiles

This suggests the Desktop webview permission UI/send path has not been updated to resolve the newer named permission profile schema, even though the runtime config parser accepts it.

Likely Root Cause

The Codex Desktop prompt/send permission writeback path appears to resolve custom permissions from legacy flat config fields rather than from:

default_permissions = "..."

[allowed_permission_profiles]

[permissions.<profile>]

When the active config uses only the named permission profile schema, the Desktop webview's custom path sees no sandbox_mode and falls back to read-only.

Possible Workaround

Adding the legacy flat fields alongside the named permission profile may work around the Desktop prompt-time resolver:

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

[sandbox_workspace_write]
network_access = true

This workaround targets the schema that the packaged Desktop webview appears to read. It does not explain or fix the underlying mismatch between the runtime's named permission profile support and the Desktop webview's prompt-time permission writeback path.

Suggested Fix Area

Please inspect the Desktop webview permission resolver and prompt-time thread settings update path, especially:

/webview/assets/src-DEDxOnN6.js
  Xf(...)
  Yf(...)
  qf(...)

/webview/assets/use-permissions-mode-9OJM2a7p.js
  update-thread-settings-for-next-turn

/webview/assets/build-start-conversation-params-BWnyzAKG.js
  permission construction for start-conversation

/webview/assets/config-queries-BAeIrVPL.js
  read-config-for-host result shape consumed by the webview

The relevant fix is likely to make the Desktop custom-mode resolver use the fully resolved permission profile from config, including default_permissions and [permissions.<profile>], rather than falling back to readOnly when legacy sandbox_mode is absent.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗