Codex Desktop switches between Ask for approval and a named profile, mismatching reviewer and sandbox

Open 💬 1 comment Opened Jul 16, 2026 by caldwellshane

Summary

Codex Desktop can silently switch the composer permission selection between Ask for approval and a named permission profile. The selected UI label, live approval reviewer, and effective filesystem policy can disagree.

Two fresh local tasks reproduced opposite unsafe states:

  1. Ask for approval produced approvals_reviewer="user", but a path explicitly denied by the named profile remained readable.
  2. When the user submitted a correction, the composer visibly switched from Ask for approval to the named profile without the user changing it.
  3. A task enforcing the named profile's filesystem deny reported approvals_reviewer="auto_review", even though both tracked and live config requested approvals_reviewer = "user".

This prevents the documented combination of a least-privilege sandbox boundary and user-reviewed approvals.

Environment

  • Codex Desktop: 26.707.91948 (build 5440)
  • Codex CLI/runtime: 0.144.5
  • macOS: 26.5.1 (25F80)
  • Reproduced: July 16, 2026
  • The behavior has occurred across fresh and resumed Desktop tasks.

Sanitized configuration

Both tracked config and live ~/.codex/config.toml contain:

approval_policy = "on-request"
approvals_reviewer = "user"
default_permissions = "custom-multi-root-profile"

The named profile grants parent traversal but explicitly denies task-history state:

[permissions."custom-multi-root-profile".filesystem]
"/Users/example/.codex" = "read"
"/Users/example/.codex/session_index.jsonl" = "deny"
"/Users/example/.codex/session_index.jsonl.*" = "deny"
"/Users/example/.codex/history.jsonl" = "deny"
"/Users/example/.codex/sessions" = "deny"
"/Users/example/.codex/sessions/**" = "deny"

Reproduction

Case A: Ask uses the user reviewer but does not enforce the named deny

  1. Start a new local Codex Desktop task.
  2. Select Ask for approval beneath the composer.
  3. Submit a prompt.
  4. Confirm the live task context reports:

``text
approval_policy="on-request"
approvals_reviewer="user"
``

  1. Attempt a real file open against the representative denied path:

``sh
/usr/bin/python3 -c 'import sys; f=open(sys.argv[1], "rb"); f.close()' /Users/example/.codex/session_index.jsonl
``

  1. Observed:

``text
Exit code: 0
Output: <empty>
``

The file opens successfully, so the named-profile deny is not active.

  1. Submit a correction in the same task.
  2. Observe the permissions selector change from Ask for approval to the named profile during submission, without the user changing it.
  3. The effective runtime policy still does not reliably match the newly displayed profile label.

Case B: The named profile enforces the deny but routes approvals to automatic review

  1. Use a task whose effective filesystem policy contains the named deny.
  2. Run the same Python file-open command.
  3. Observe PermissionError: [Errno 1] Operation not permitted, confirming the named deny is active.
  4. Inspect the live task context.
  5. Observed:

``text
approval_policy="on-request"
approvals_reviewer="auto_review"
``

  1. Compare with tracked and live config, which both request:

``toml
approvals_reviewer = "user"
``

Additional policy checks

A focused read-only audit reported:

tracked_config: approval_policy='on-request'; approvals_reviewer='user'
live_config: approval_policy='on-request'; approvals_reviewer='user'
project_config: absent
/etc/codex/requirements.toml: absent
live_task_context: approvals_reviewer='auto_review'

Visible cloud requirements contained no allowed_approvals_reviewers or other visible rule forcing auto_review.

Expected behavior

Codex documentation describes two controls that work together:

  • The sandbox controls accessible files and network resources.
  • Approval routing determines whether the user or automatic reviewer handles an escalation.
  • Changing who reviews a request should not expand the sandbox.

Therefore:

  • A named filesystem/network profile should coexist with approvals_reviewer = "user".
  • The selected permission setting should remain stable unless the user changes it.
  • The UI label, live task context, and effective sandbox should identify the same active policy.
  • If settings cannot be reconciled, the product should fail closed rather than silently broadening reads or changing the reviewer.

Actual behavior and impact

  • Ask for approval restores the user reviewer but does not enforce the required named-profile denies.
  • The named profile can enforce the denies but may route approvals to automatic review.
  • The selected mode can change during message submission.
  • The UI label can disagree with the effective filesystem policy.
  • Restarting, starting fresh tasks, and reselecting the mode have not produced a durable repair.

This is a security and reliability problem: one state broadens access to local task-history artifacts, while the other changes who reviews escalations.

Related issues

  • #22553: Desktop shows a custom profile selection but does not apply its effective permissions.
  • #23875: Desktop loses approvals_reviewer state after context reconstruction.
  • #23958: A session's permission profile changes without an explicit permission command.

This report is distinct because it has a deterministic Desktop UI transition plus a two-task comparison demonstrating both sides of the mismatch: user reviewer without the named deny, and named deny with the wrong reviewer.

Requested repair

  1. Preserve the selected permission profile and approvalsReviewer independently across task start, resume, and turn submission.
  2. Prevent message submission from changing the composer permission selection without explicit user action.
  3. Make the UI label, task context, and effective sandbox agree.
  4. Expose a supported effective-settings diagnostic showing the active permission profile, approval policy, approvals reviewer, and configuration layer or task override.
  5. Fail closed if task settings cannot be reconciled.

Private task identifiers and screenshots are available to OpenAI maintainers through a non-public channel if needed.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗