openai / openai/codex

Codex desktop: permission state (activePermissionProfile/approvalPolicy/writableRoots) silently degrades to :workspace + sandbox_approval: false over successive read-only turns in the same task

Open
#40,698 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app bug sandbox session windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

Summary
Within a single Codex desktop task, the effective permission state (activePermissionProfile, approvalPolicy, approvalsReviewer, writableRoots) silently degrades over successive turns — even when no files, settings, or the model are changed, and even though the on-disk config.toml defaults never change. Over three consecutive read-only status requests in one task, the state went from the correct configured profile down to bare :workspace with sandbox_approval: false and almost all writable roots removed.
This was independently confirmed by reading .codex-global-state.json directly, not just from the app's own self-reported status — the per-thread heartbeat entry in the state file matches the degraded values exactly.
Environment
Platform: Windows, Codex desktop app (please fill in exact build number from Settings → About — omitted here since it wasn't captured during the investigation)
Account: authenticated via ChatGPT; no organization-managed requirements.toml or managed_config.toml present at any documented system/user location
config.toml throughout this entire test: approval_policy = "on-request", approvals_reviewer = "user", default_permissions = "husum-property-files" — unchanged at every turn
Steps to reproduce
Start a new Codex task with a profile that has an explicit default_permissions set in config.toml (in this case, a custom profile husum-property-files).
Ask for a read-only status report of activePermissionProfile, approvalPolicy, approvalsReviewer, sandbox approval status, and writable roots.
Without making any file changes, permission changes, or model changes, ask for the identical read-only status report again.
Repeat once more.
Observed behavior (this run)
Turn 1 Turn 2 Turn 3
activePermissionProfile husum-property-files (extends :workspace) null / missing :workspace
approvalPolicy "on-request" "on-request" {"granular": {"sandbox_approval": false, "rules": false, "skill_approval": false, "request_permissions": true, "mcp_elicitations": true}}
approvalsReviewer "user" "user" "user"
writableRoots 7 entries, including the task folder, F:\Pictures\My Pictures, two OneDrive project folders, and .codex\memories same 7, plus an unrequested broader root (C:\Users\Dave Gibney\Documents\Codex, the parent of the task folder) only the task's own temp visualization directory — all 6 other roots gone, including F:\Pictures\My Pictures
Turn 3's values were independently verified against .codex-global-state.jsonelectron-persisted-atom-state.heartbeat-thread-permissions-by-id["<thread-id>"] directly on disk, and match the app's self-report exactly:

{
  "activePermissionProfile": { "id": ":workspace", "extends": null },
  "approvalPolicy": {
    "granular": {
      "sandbox_approval": false,
      "rules": false,
      "skill_approval": false,
      "request_permissions": true,
      "mcp_elicitations": true
    }
  },
  "approvalsReviewer": "user",
  "sandboxPolicy": {
    "type": "workspaceWrite",
    "writableRoots": ["C:\\Users\\<user>\\.codex\\visualizations\\2026\\08\\25\\<thread-id>"],
    "networkAccess": false,
    "excludeTmpdirEnvVar": false,
    "excludeSlashTmp": false
  }
}

Expected behavior
A task's effective permission profile, approval policy, reviewer, and writable-root allowlist should not change between turns unless the user, the config, or the model changes. Three plain read-only status requests in the same task should return identical values each time.
Additional related finding (separate but adjacent bug)
Before the above was reproduced, a different desync was found and had to be manually patched: two host-scoped keys in the same state file — electron-persisted-atom-state.agent-mode-by-host-id.local and electron-persisted-atom-state.preferred-non-full-access-agent-mode-by-host-id.local — remained stuck at "guardian-approvals" (left over from earlier "Approve for me" usage) even after permission-selection-by-host-id:local was cleared and config.toml correctly specified approvals_reviewer = "user". As long as those two keys held "guardian-approvals", new tasks' approvalsReviewer came back as auto_review regardless of config.toml. This suggests the app keeps more than one on-disk representation of "current permission mode" per host, and they can desync from each other and from config.toml. Setting agent-mode-by-host-id.local to "auto" and preferred-non-full-access-agent-mode-by-host-id.local to null (matching a known-good backup from earlier the same day) resolved that specific symptom — approvalsReviewer correctly held at "user" through all three turns of the test above, even while the separate per-turn degradation (this report's main subject) still occurred.
Impact
Permission-dependent file operations (in this case, work on personal photo files) cannot be safely performed partway through a task, since the writable-root allowlist and sandbox approval behavior cannot be trusted to hold steady even across read-only turns. The only currently-known-reliable point is the first turn of a brand-new task.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the three read-only turns on Windows and inspect .codex-global-state.json, especially electron-persisted-atom-state.heartbeat-thread-permissions-by-id and the related host-scoped keys. Compare each turn with config.toml; done means the effective permission profile, approval policy, reviewer, and writableRoots remain unchanged when no inputs change.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop-dev, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.