Codex CLI Permissions and Sandbox Reference
Updated by Alex Sorokoletov
Independent reference, not affiliated with OpenAI. Tables are generated from the Codex CLI source at rust-v0.159.2 (v0.159.2). Official documentation: learn.chatgpt.com.
Codex CLI limits commands in two ways: a sandbox decides which files and network a command can reach, and an approval policy decides when Codex asks you first. The sandbox comes from legacy sandbox_mode or from permission profiles selected by default_permissions, with built-ins :read-only, :workspace and :danger-full-access. Administrators can lock both in requirements.toml.
What are Codex sandbox modes?#
sandbox_mode takes three values, each equivalent to a built-in permission profile. Only requirements.toml accepts a fourth value, external-sandbox.
| sandbox_mode | Accepted in |
|---|---|
read-only | config.toml, -s/--sandbox, requirements.toml |
workspace-write | config.toml, -s/--sandbox, requirements.toml |
danger-full-access | config.toml, -s/--sandbox, requirements.toml |
external-sandbox | requirements.toml allowed_sandbox_modes only |
| Profile | Same as sandbox_mode | Filesystem | Network | Usable in extends |
|---|---|---|---|---|
:read-only | read-only | :root read | off | yes |
:workspace | workspace-write | :root read, :workspace_roots write, :slash_tmp write, :tmpdir write | off | yes |
:danger-full-access | danger-full-access | no sandbox | unrestricted | no |
:workspace reads everywhere and writes to the workspace roots (the working directory plus any --add-dir directories), /tmp and $TMPDIR, with network off. The legacy [sandbox_workspace_write] table tunes the same thing:
| [sandbox_workspace_write] key | Type | Default | Notes |
|---|---|---|---|
exclude_slash_tmp | boolean | false | — |
exclude_tmpdir_env_var | boolean | false | — |
network_access | boolean | false | — |
writable_roots | string[] | [] | — |
The sandbox is enforced by the operating system:
| OS | Sandbox |
|---|---|
| macOS | Seatbelt via /usr/bin/sandbox-exec |
| Linux | bubblewrap by default; Landlock with the use_legacy_landlock feature |
| Windows | selected with [windows] sandbox = elevated | unelevated | mxc |
What approval policies does Codex support?#
| approval_policy | Alias | Accepted in | Behaviour |
|---|---|---|---|
untrusted | — | rejected in config.toml | Internal policy for projects marked untrusted. Commands require approval unless an explicit exec policy rule allows them. |
on-request | on-failure | config.toml, -a/--ask-for-approval | The model decides when to ask the user for approval. |
granular | — | config.toml as { granular = { ... } } | Fine-grained controls for individual approval flows. |
never | — | config.toml, -a/--ask-for-approval | Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval. |
With no approval_policy set, Codex uses on-request, except for projects marked untrusted, which get the internal untrusted policy. granular answers each kind of prompt separately: true lets that kind reach you, false rejects it automatically without asking.
approval_policy = { granular = { sandbox_approval = true, rules = true, mcp_elicitations = false } }
| Key | Type | Default | Notes |
|---|---|---|---|
mcp_elicitations | boolean | — | Whether to allow MCP elicitation prompts. |
request_permissions | boolean | false | Whether to allow prompts triggered by the `request_permissions` tool. |
rules | boolean | — | Whether to allow prompts triggered by execpolicy `prompt` rules. |
sandbox_approval | boolean | — | Whether to allow shell command approval requests, including inline `with_additional_permissions` and `require_escalated` requests. |
skill_approval | boolean | false | Whether to allow approval prompts triggered by skill script execution. |
approvals_reviewer decides who answers an escalated request. auto_review sends it to a reviewer subagent instead of you; guardian_subagent is the legacy name for the same value.
| approvals_reviewer |
|---|
user |
auto_review |
guardian_subagent |
What is the difference between sandbox mode and approval policy?#
The sandbox is the hard boundary: a command in :workspace cannot write outside the workspace roots whatever the model intends. The approval policy only governs what happens when a command needs more than the sandbox allows, or a rule asks for confirmation: on-request lets the model ask you, never returns the failure to the model without asking. never with :read-only gives an agent that can read but never change anything and never prompts.
How do Codex permission profiles work?#
A profile is a named [permissions.<name>] table, selected with default_permissions = "<name>". It can extends :read-only, :workspace or another profile of yours, then adds filesystem entries and network settings on top; child keys override the parent's. Names starting with : are reserved for built-ins, and :danger-full-access cannot be extended.
default_permissions = "dev"
[permissions.dev]
extends = ":workspace"
description = "Workspace write, one secret hidden, network on"
[permissions.dev.filesystem]
"/srv/secrets" = "deny"
[permissions.dev.network]
enabled = true
Filesystem values are read, write or deny (none is a legacy alias of deny). When two equally specific entries target the same path, deny beats write and write beats read. Besides absolute paths, entries accept these tokens; unknown :tokens are warned about and ignored, so a newer config still loads:
| Path token | Alias |
|---|---|
:root | — |
:minimal | — |
:workspace_roots | :project_roots |
:tmpdir | — |
:slash_tmp | — |
| [permissions.<name>] key | Type | Default | Notes |
|---|---|---|---|
description | string | — | — |
extends | string | — | — |
filesystem | object | — | — |
filesystem.glob_scan_max_depth | integer | — | Optional maximum depth for expanding unreadable glob patterns on platforms that snapshot glob matches before sandbox startup. |
network | object | — | — |
network.allow_local_binding | boolean | — | Permits local servers and direct host-loopback connections and skips the proxy's additional private-network destination checks. Proxy domain rules still apply. Defaults to true for MXC, which cannot enforce false; otherwise defaults to false. |
network.allow_upstream_proxy | boolean | — | — |
network.dangerously_allow_all_unix_sockets | boolean | — | — |
network.dangerously_allow_non_loopback_proxy | boolean | — | — |
network.domains | object | — | — |
network.enable_socks5 | boolean | — | — |
network.enable_socks5_udp | boolean | — | — |
network.enabled | boolean | — | — |
network.mitm | object | — | — |
network.mitm.actions | object | — | — |
network.mitm.hooks | object | — | — |
network.mode | limited | full | — | — |
network.proxy_url | string | — | — |
network.socks_url | string | — | — |
network.unix_sockets | object | — | — |
workspace_roots | object | — | — |
sandbox_mode or default_permissions: which one wins?#
Both keys still work in 0.159.2. Codex decides per session which model applies:
| Configuration | Effective permissions |
|---|---|
| -s/--sandbox on the command line | legacy sandbox_mode wins for this run |
| -c default_permissions=... on the command line | permission profiles win for this run |
| Both keys across config layers | the highest-precedence layer that sets either key decides; in the same layer default_permissions wins |
| Neither key set | :workspace when the project has a trust decision, else :read-only (also :read-only on Windows with the sandbox disabled) |
| [sandbox_workspace_write] with profiles | applied to the implicit :workspace default only; an explicit default_permissions = ":workspace" ignores it |
| [permissions] defined, default_permissions unset | startup error: "config defines `[permissions]` profiles but does not set `default_permissions`" |
| Profile name starting with : | rejected: reserved for built-in profiles |
| approval_policy unset | on-request, except the internal untrusted policy for projects marked untrusted |
So with nothing configured, a trusted repository gets :workspace with on-request approvals, an untrusted one gets :workspace with untrusted approvals, and a directory with no trust decision gets :read-only.
Why are my Codex permissions locked by requirements.toml?#
requirements.toml is the administrator's file. Its allowed_* lists limit which values your config may choose, and a few keys such as default_permissions pin a value outright. It is read from the system location, enterprise cloud bundles and macOS managed preferences, never from your user or project config.
allowed_approval_policies = ["on-request"]
allowed_sandbox_modes = ["read-only", "workspace-write"]
| requirements.toml key | Type | Values | Alias |
|---|---|---|---|
allowed_approval_policies | list of AskForApproval | untrusted, on-request, granular, never | — |
allowed_approvals_reviewers | list of ApprovalsReviewer | user, auto_review, guardian_subagent | — |
allowed_sandbox_modes | list of SandboxModeRequirement | read-only, workspace-write, danger-full-access, external-sandbox | — |
allowed_permission_profiles | table of boolean | <profile id> = true | false | — |
default_permissions | string | — | — |
permissions | table | — | — |
experimental_network | table | — | — |
allow_managed_hooks_only | boolean | — | — |
rules | table | — | — |
features | table | — | feature_requirements |
| Situation | What Codex does |
|---|---|
| Configured value outside an allowed_* list | falls back to the required value with a startup warning "Configured value for `<field>` is disallowed by requirements" |
| approval_policy = "never" when danger-full-access is not allowed | startup error instead of a silent read-only session with approvals off |
| Profile not in allowed_permission_profiles | shown as "Disabled by requirements" in the permissions picker |
| requirements.toml location | /etc/codex/requirements.toml, %ProgramData%\OpenAI\Codex\requirements.toml on Windows, plus cloud bundles and macOS managed preferences |
Is there a Codex equivalent of --dangerously-skip-permissions?#
Yes: --dangerously-bypass-approvals-and-sandbox, aliased --yolo. It runs every command without a sandbox and without asking, and is meant for environments that are already sandboxed from outside, such as a disposable container. --approve-for-me keeps the workspace-write sandbox and routes approval requests to the automatic reviewer instead of you.
| Flag | Alias | Help text |
|---|---|---|
--sandbox, -s | — | Select the sandbox policy to use when executing model-generated shell commands. |
--approve-for-me | --not-so-yolo | Route approval requests through automatic review using the workspace-write sandbox. |
--dangerously-bypass-approvals-and-sandbox | --yolo | Skip all confirmation prompts and execute commands without sandboxing. EXTREMELY DANGEROUS. Intended solely for running in environments that are externally sandboxed. |
--dangerously-bypass-hook-trust | — | Run enabled hooks without requiring persisted hook trust for this invocation. DANGEROUS. Intended only for automation that already vets hook sources. |
--add-dir | — | Additional directories that should be writable alongside the primary workspace. |
--ask-for-approval, -a | — | Configure when the model requires human approval before executing a command. |
| Flag | Equivalent to |
|---|---|
--dangerously-bypass-approvals-and-sandbox | sandbox danger-full-access + approval never |
--approve-for-me | approvals_reviewer auto_review + approval on-request + sandbox workspace-write |
--dangerously-bypass-hook-trust | runs enabled hooks without review for this invocation |
How do I allow network access in workspace-write?#
Network is off in :workspace and workspace-write by default. The switch depends on which permission model is active:
| Setting | Effect |
|---|---|
[sandbox_workspace_write] network_access = true | legacy switch for workspace-write; default false |
[permissions.<name>.network] enabled = true | profile switch for sandbox network access; proxy settings in the profile do not start the managed proxy by themselves |
[features] network_proxy = true | starts the managed network proxy for sandboxed sessions |
:danger-full-access / danger-full-access | no sandbox, unrestricted network |
| Key | Stage | Default | What it does | Legacy alias |
|---|---|---|---|---|
exec_permission_approvals | under development | off | Allow exec tools to request additional permissions while staying sandboxed. | request_permissions |
request_permissions_tool | under development | off | Expose the built-in request_permissions tool. | — |
use_legacy_landlock | deprecated | off | Use the legacy Landlock Linux sandbox fallback instead of the default bubblewrap pipeline. | — |
experimental_windows_sandbox | removed | off | Enable Windows sandbox (restricted token) on Windows. | enable_experimental_windows_sandbox |
elevated_windows_sandbox | removed | off | Use the elevated Windows sandbox pipeline (setup + runner). | — |
network_proxy | experimental | off | Start the managed network proxy for sandboxed sessions. | — |
Frequently asked questions#
What are Codex sandbox modes?#
read-only lets commands read files but not write them or use the network; workspace-write also lets them write inside the workspace roots, /tmp and $TMPDIR; danger-full-access removes the sandbox. They correspond to the built-in permission profiles :read-only, :workspace and :danger-full-access. Set one with sandbox_mode in config.toml or -s on the command line.
What is the difference between sandbox mode and approval policy?#
The sandbox limits what a command can touch; the approval policy decides whether Codex asks you when a command needs more. on-request lets the model ask for escalation, never sends failures straight back to the model, and granular accepts or rejects each prompt type separately. They combine: workspace-write with on-request is the usual interactive setup.
How do I stop Codex from always asking for approval?#
Set approval_policy = "never" (or run with -a never) to stop prompts while keeping the sandbox; blocked commands then fail back to the model. --approve-for-me hands prompts to an automatic reviewer and keeps workspace-write. Trusting the project also helps, because untrusted projects use the stricter internal untrusted policy. Only --yolo removes both prompts and sandbox.
Is there a Codex equivalent of --dangerously-skip-permissions?#
--dangerously-bypass-approvals-and-sandbox, also accepted as --yolo, is the equivalent: it sets danger-full-access and approval never for the run. The flag conflicts with -a in the interactive CLI. Use it only inside an environment that is sandboxed externally, because Codex then runs commands with your full user permissions.
Why are Codex permissions locked by requirements.toml?#
An administrator's requirements.toml (in /etc/codex/, %ProgramData%\OpenAI\Codex\, a cloud bundle or macOS managed preferences) restricts which approval policies, sandbox modes and permission profiles are allowed. A value outside the list falls back to an allowed one with a startup warning, and profiles it excludes show "Disabled by requirements". Only the administrator can change it.
How do I allow network access in Codex workspace-write mode?#
With the legacy model, set network_access = true under [sandbox_workspace_write]. With permission profiles, add [permissions.<name>.network] with enabled = true to the profile named in default_permissions. Note that an explicit default_permissions = ":workspace" ignores the legacy table, so the network switch must then live in a custom profile that extends :workspace.
Does default_permissions replace sandbox_mode?#
Not yet: both work in 0.159.2. When both are set, the highest-precedence config layer that sets either decides, default_permissions wins inside a single layer, and -s on the command line forces the legacy key for that run. Defining [permissions] profiles without default_permissions is a startup error.
Sources
- Codex CLI official documentation
- Codex CLI release notes
codex-rs/core/config.schema.json: config.toml JSON Schema (sandbox, approvals, [permissions]) (at rust-v0.159.2)codex-rs/protocol/src/models.rs: built-in permission profile ids (at rust-v0.159.2)codex-rs/core/src/config/permissions.rs: built-in profiles, default selection, special paths (at rust-v0.159.2)codex-rs/protocol/src/permissions.rs: filesystem entries of the built-in profiles (at rust-v0.159.2)codex-rs/config/src/config_requirements.rs: requirements.toml fields (at rust-v0.159.2)codex-rs/protocol/src/protocol.rs: AskForApproval enum (at rust-v0.159.2)codex-rs/utils/cli/src/approval_mode_cli_arg.rs: values accepted by -a/--ask-for-approval (at rust-v0.159.2)codex-rs/core/src/config/mod.rs: permission selection and approval defaults (at rust-v0.159.2)codex-rs/utils/cli/src/shared_options.rs: shared CLI flags (at rust-v0.159.2)codex-rs/tui/src/cli.rs: interactive CLI flags (at rust-v0.159.2)codex-rs/tui/src/startup_orchestration.rs(at rust-v0.159.2)codex-rs/features/src/lib.rs(at rust-v0.159.2)codex-rs/tui/src/permission_discovery.rs(at rust-v0.159.2)codex-rs/config/src/loader/mod.rs(at rust-v0.159.2)codex-rs/sandboxing/src/seatbelt.rs(at rust-v0.159.2)codex-rs/config/src/types.rs(at rust-v0.159.2)codex-rs/features/src/legacy.rs: legacy feature keys (at rust-v0.159.2)
Release-by-release changes: Codex CLI version tracker. All Codex CLI pages: Codex CLI reference index.