Codex beta permission restrictions are not disabled after asking for escalation

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

Codex version

Version 26.623.101652 • Released Jul 3, 2026
codex-cli 0.141.0

What subscription do you have?

Business

What platform is your computer?

Darwin 25.5.0 arm64 arm

What issue are you seeing?

I'm on the security conscious side and love the concepts around rules, hooks and the new permission profiles. However, in addition to them being confusing in how they relate to each other and to the older sandboxing configuration, they don't seem to work properly for me.

More concretely: When a command is rightfully rejected and afterwards, codex asks to rerun with escalation and I approve, the restrictions still seem to be in place and the command fails just like in the sandbox.

This makes my more restrictive profile largely useless.
Switching profiles is not really an alternative either because the great strength of the approval workflow is approving the EXACT command codex wants to run.

What is the expected behavior?

After asking for approval, the one approved command should run completely outside of the sandbox restrictions.

Alternatively, codex could ask to escalate to another named sandbox profile, which would make the behaviour even more explicit.

Additional information

For context, these are all of my broadly permission-specific settings from config.toml:

default_permissions = "workspace-only"

[permissions.workspace-write-read-all]
extends = ":workspace"
[permissions.workspace-write-read-all.filesystem]
":tmpdir" = "deny"
":slash_tmp" = "deny"
"~/.codex-cache" = "write"
[permissions.workspace-write-read-all.network]
enabled = true
[permissions.workspace-write-read-all.network.domains]
"*" = "allow"

[permissions.workspace-only.filesystem]
#":root" = "deny"
":minimal" = "read"
":tmpdir" = "deny"
":slash_tmp" = "deny"
"~/.codex-cache" = "write"
"~/.codex" = "read"

"/opt/homebrew" = "read"
"~/.asdf" = "read"

"~/Development/ceres" = "read"
"~/.ceres" = "read"

"/Library/Developer/CommandLineTools" = "read"
"~/.gitconfig" = "read"
"~/.npmrc" = "read"

[permissions.workspace-only.filesystem.":workspace_roots"]
"." = "write"
".codex" = "read"
".git" = "read"
"module/**" = "read"
"system.sh" = "read"
# "frontend/src" = "write"
# "frontend/src/server" = "write"
# "api/generator-config" = "write"
# "api/specs" = "write"
# "api/openapi-spec.yml" = "write"
# "e2e-test/src" = "write"

[permissions.workspace-only.network]
enabled = true

[permissions.workspace-only.network.domains]
"redacted_internal_domain1" = "allow"
"redacted_internal_domain2" = "deny"

[shell_environment_policy]
set = {
  PATH = "/opt/homebrew/bin:/opt/homebrew/sbin:/Users/hrisser/.asdf/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
  TMPDIR = "/Users/hrisser/.codex-cache/tmp",
  TEMP = "/Users/hrisser/.codex-cache/tmp",
  TMP = "/Users/hrisser/.codex-cache/tmp",
  GRADLE_USER_HOME = "/Users/hrisser/.codex-cache/gradle",
  GRADLE_OPTS = "-Dorg.gradle.daemon=false",
  npm_config_cache = "/Users/hrisser/.codex-cache/npm-cache",
  YARN_CACHE_FOLDER = "/Users/hrisser/.codex-cache/yarn-cache",
  MAVEN_OPTS = "-Dmaven.repo.local=/Users/hrisser/.codex-cache/m2",
  JAVA_TOOL_OPTIONS = "-Duser.home=/Users/hrisser/.codex-cache/home -Dmaven.repo.local=/Users/hrisser/.codex-cache/m2"
}

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 1 month ago

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

  • #30898

Powered by Codex Action

rpelevin · 1 month ago

I would separate this into two state transitions: policy profile selected versus command execution profile granted.

The approval prompt should not only mean "rerun with escalation". It should bind one command digest to one explicit execution profile.

Useful invariants:

  • the rejected run records the profile and denial reason that blocked it;
  • the approval records the exact command digest, requested capability delta, and target profile;
  • the retry executes under that approved profile or does not execute;
  • the user-visible UI and runtime context report the same effective profile;
  • denial after approval names a new reason instead of reusing the original sandbox failure.

Regression cases:

  • command denied by filesystem sandbox, approval grants filesystem-only profile, retry succeeds or reports a new reason;
  • command denied by network sandbox, approval grants network-enabled profile, retry has network access;
  • approval is for one command digest and cannot be replayed against a mutated command;
  • approval expires or is rejected, retry remains no-effect;
  • selected profile changes between prompts, retry recomputes authority before execution.

The important boundary is that escalation is a typed transition, not a boolean override. If the runtime keeps executing under the old profile after approval, the audit record says "approved" while the effect path still says "denied", which is exactly the contradiction users cannot debug.