exec: approvals_reviewer = "auto_review" silently defeats an explicit --sandbox level

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

What happens

Under codex exec, approvals_reviewer = "auto_review" causes an explicit --sandbox read-only to be accepted and then not enforced. The level appears in the session header, the turn runs, and writes succeed anyway. Nothing in the output indicates the requested level was not applied.

auto_review delegates approval of a sandbox escalation to a model rather than to a person. That is coherent in an interactive session, where the alternative is prompting the user. In exec there is no user to prompt, so the escalation is simply granted, and the level passed on the command line stops being a boundary.

Reproduction

Verified on codex-cli 0.146.0, Linux. Self-contained, using a throwaway CODEX_HOME so it does not depend on any existing config:

rm -rf /tmp/h /tmp/w && mkdir -p /tmp/h /tmp/w
cp ~/.codex/auth.json /tmp/h/
printf 'approvals_reviewer = "auto_review"\n' > /tmp/h/config.toml

cd /tmp/w
CODEX_HOME=/tmp/h codex exec --sandbox read-only --skip-git-repo-check \
  -- "Run exactly this shell command: echo WROTE > x.txt"

Result: x.txt is created. Final agent message is `Command completed successfully. x.txt now contains WROTE.`

Now change the single key and repeat:

rm -f /tmp/w/x.txt
printf 'approvals_reviewer = "user"\n' > /tmp/h/config.toml

cd /tmp/w
CODEX_HOME=/tmp/h codex exec --sandbox read-only --skip-git-repo-check \
  -- "Run exactly this shell command: echo WROTE > x.txt"

Result: no file. Final agent message reports `/bin/bash: line 1: x.txt: Read-only file system`.

Same command, same flag, opposite enforcement, one config key apart.

Scope

Things I checked while narrowing this down, in case they save time:

  • Both write mechanisms escape: the native file-editing tool and a plain shell redirect. The example above uses the shell because its failure message is unambiguous when the sandbox does hold.
  • Applies to fresh turns and to turns resumed with codex exec resume.
  • Applies in trusted and untrusted directories alike, so project trust is not the deciding factor.
  • Not caused by the model in use: pinning the same model with --ignore-user-config still enforces the level, so the difference is the config key rather than model behaviour.
  • The key has a second route in. Codex also loads a project-local .codex/config.toml, and approvals_reviewer is not in PROJECT_LOCAL_CONFIG_DENYLIST, so a repository can carry auto_review in-tree. That layer is gated on the project being trusted in user config, but a single broad entry such as [projects."/home/me"] trust_level = "trusted" makes every repository beneath it eligible. I reproduced the same bypass this way with a trusted directory whose only config was an in-tree .codex/config.toml.

Why this seems worth reporting

The failure is silent and it fails open. A caller that explicitly asked for read-only gets writes, and the response gives no indication that the level was set aside, so the party relying on the boundary is the one who cannot see it was dropped.

It also inverts the precedence people expect: an explicit command-line flag loses to a value in a config file. Non-interactive callers such as CI jobs, harnesses, and MCP servers inherit the invoking user's config by default, so the config that disables the boundary is often not written by whoever is passing --sandbox.

I am not proposing a specific change here, since the right resolution depends on how auto_review is intended to behave when there is no interactive approver, which is a design question for the maintainers. Reporting the behaviour and the repro.

Workaround

Passing -c approvals_reviewer="user" restores enforcement. The runtime override outranks both the user config and the project-local layer; I verified it against both routes.

Environment

  • codex-cli 0.146.0
  • Linux, x86_64
  • Reproduced originally on 0.145.0 and re-verified on 0.146.0

---

Investigated with the help of an AI coding agent. Every command and result above was executed and verified, not inferred.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 26 days ago

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

  • #36448

Powered by Codex Action

hampsterx · 25 days ago

Not a duplicate of #36448. That report is about resolution order between default_permissions and sandbox_mode; this one is approvals_reviewer handing escalation approval to a model in a context with no human to refuse it. Different key, different mechanism, and the repro in #36448 does not produce this.

The mechanism is in codex-rs/prompts/src/permissions_instructions.rs: AUTO_REVIEW_APPROVAL_SUFFIX reads "Sandbox escalations with require_escalated will be reviewed for compliance with the policy". Under exec that review has no fallback to a person, so the escalation is granted and the level passed in argv becomes advisory rather than binding.

Related but also not duplicates: #12896 is the interactive case where a human granted the approval, and #27277 is the same failure shape one layer up, where the SDK's default handler auto-accepts the escalation request.

antonnymello · 5 days ago

I can independently confirm this is still reproducible on codex-cli 0.149.0.

I tested with:

approval_policy="on-request"
approvals_reviewer="auto_review"
--sandbox read-only

Using Luna/xhigh, I asked Codex to execute:

echo WROTE > x.txt

The command returned exit code 0 and x.txt was actually created, despite the explicit --sandbox read-only.

As a control, I changed only:

approvals_reviewer="user"

and repeated the test. This time the file was not created and Codex correctly reported the filesystem as read-only.

So the behavior reported here is still present in 0.149.0.

One additional observation: with lower reasoning, the model sometimes recognizes that the operation should not be allowed and doesn't attempt the escalation at all. With xhigh, it did request/perform the escalation and reproduced the bypass. This can make the bug appear intermittent depending on model behavior, but the important part is that the sandbox boundary itself cannot be relied upon when approvals_reviewer="auto_review" is enabled.

For now, overriding it with:

-c 'approvals_reviewer="user"'

restores the expected read-only enforcement in my testing.