Codex Permission Profiles: Least-Privilege Controls for Local Agent Work
OpenAI shipped Codex permission profiles in beta -- reusable, inheritable policies that replace the coarse sandbox_mode/sandbox_workspace_write combo. A profile binds OS-enforced filesystem read/write/deny rules (down to **/*.env) to per-domain network and Unix-socket rules. Enterprise admins get fail-closed allowlists via requirements.toml. Profiles govern local sandboxed command execution only, not MCP servers, app connectors, browser, or cloud.
OpenAI shipped a replacement for Codex's coarse sandbox modes: reusable, inheritable permission profiles that bind OS-enforced filesystem read/write/deny rules -- down to **/*.env -- to per-domain network and Unix-socket policies, plus fail-closed admin allowlists. A profile is a single named policy that describes least-privilege boundaries for the local commands Codex runs on your behalf. The feature is beta and under active development, and it governs local sandboxed command execution only -- not MCP servers, app connectors, the browser, or Codex cloud.
This is the policy layer that sits underneath the automation surface we covered in Codex hooks and programmatic access tokens, and it complements the per-site browser controls in the Codex Chrome extension. For where Codex's local execution model sits relative to its peers, see our Codex CLI vs Claude Code vs Cursor architecture comparison.
Key Takeaways
- Profiles replace coarse sandbox modes. A permission profile supersedes the older
sandbox_mode+sandbox_workspace_writecombination when you want one reusable, inheritable policy for filesystem and network behavior. - They do not compose with the old settings. Configure either
default_permissions+[permissions]or the legacy sandbox settings -- not both. The only exception is enterprise managedallowed_permission_profiles, which overrides older sandbox settings. - Three built-ins:
:read-only,:workspace, and:danger-full-access. Custom profiles live under[permissions.<name>];default_permissionsselects the active one. - Filesystem precedence is deny > write > read. Narrow
denyrules survive even when a broader path is writable -- the canonical example is**/*.env = denyinside:workspace_roots. - Network is default-block. With no allow entries, outbound is blocked;
denyoverridesallow; wildcard allow (*) is opt-in; localhost and private IPs require explicit allowlisting; Unix sockets (for example Docker) are an explicit escape hatch. - Fail-closed admin allowlists.
allowed_permission_profilesinrequirements.tomldenies any omitted profile, including built-ins and future profiles. Requires Codex 0.138.0+. - Scope is local commands only. Profiles do not govern MCP, app connectors, browser/computer-use, or cloud. If the sandbox can't enforce a policy, Codex refuses rather than running unsandboxed.
What a Permission Profile Is
A permission profile is a named policy that combines filesystem rules and network rules into one reusable, inheritable unit. Per the official docs, profiles "replace the older combination of sandbox_mode and sandbox_workspace_write" when you want a single reusable definition of how Codex's local commands may touch the filesystem and the network.
The critical constraint up front: profiles do not compose with the legacy settings. You pick one system. Configure default_permissions plus [permissions.<name>] sections, or configure sandbox_mode/sandbox_workspace_write -- mixing the two is not supported. The single exception is enterprise managed allowed_permission_profiles, which overrides older sandbox settings entirely.
Three built-in profiles ship out of the box:
| Built-in | Behavior |
|---|---|
:read-only | Blocks local command modifications |
:workspace | Permits writes within active workspace roots and the system temp directory |
:danger-full-access | Removes local sandbox restrictions -- use only when broad access is intentional |
You select the active profile by setting default_permissions to a built-in or to a custom profile defined under [permissions.<name>].
Filesystem Rules: Deny Wins
Filesystem entries use three access levels, and their precedence is the most important thing to internalize. read allows viewing files and listing directories. write allows read plus create, rename, and delete. deny blocks both. More specific paths override broader ones, and at equal specificity deny wins over write, which wins over read.
The practical payoff is that a narrow deny rule stays in force even when a broader path is readable or writable. The docs' headline example is keeping secrets out of reach while a workspace is otherwise writable:
[permissions.project-edit.filesystem]
glob_scan_max_depth = 3
[permissions.project-edit.filesystem.":workspace_roots"]
"**/*.env" = "deny"
glob_scan_max_depth (minimum 1) bounds how far Codex pre-expands an unbounded ** pattern, so a recursive deny glob doesn't trigger an unbounded filesystem scan. Path targets include symbolic roots like :workspace_roots, :tmpdir, and :minimal, as well as absolute and home-relative paths. Note one portability caveat from the docs: deny-read globs are portable, but read/write globs may require exact paths or subtree rules depending on platform.
Network Rules: Default-Block, Per-Domain
Network access is off until you turn it on (network.enabled = true), and even then the model is allow-listed: with no allow entries, outbound connections are blocked. Domain patterns support exact hosts (example.com), subdomain wildcards (*.example.com), apex-plus-subdomain (**.example.com), and a global * that deny rules can narrow. As with the filesystem, deny overrides allow.
Two guards matter for anyone wiring profiles into real workflows:
- Local and private targets are blocked by default.
localhostand private IPs need explicit allowlisting; resolving allowlisted hostnames to local addresses additionally requiresallow_local_binding = true. This stops a sandboxed command from quietly reaching your other local services. - Unix sockets are an explicit, sparing escape hatch. Local integrations like Docker can be permitted through
network.unix_sockets, for example"/var/run/docker.sock" = "allow". The docs frame these as something to use sparingly, since a socket grant can be a wide door.
[permissions.project-edit.network]
enabled = true
[permissions.project-edit.network.domains]
"**.github.com" = "allow"
[permissions.project-edit.network.unix_sockets]
"/var/run/docker.sock" = "allow"
Inheritance and Enterprise Allowlists
Profiles use config-layer inheritance. Higher-precedence config layers can add to or replace entries under the same profile name, and a profile can extends a built-in (:read-only or :workspace) or another named profile. You cannot extend :danger-full-access -- there is no least-privilege story to build on top of "no restrictions."
The enterprise lever is allowed_permission_profiles in a managed requirements.toml. Admins define which profiles exist and restrict which ones users may select. The behavior is fail-closed: once allowed_permission_profiles is present, any profile not on the list is denied -- including omitted built-ins and any profiles added in future Codex versions. That is the security-correct default: a new profile nobody has vetted is unavailable until an admin adds it, rather than silently selectable. Managed allowed_permission_profiles requires Codex 0.138.0 or later and overrides older sandbox settings entirely.
Scope and Enforcement: Read the Caveats
Two caveats are load-bearing and easy to overclaim past.
Profiles govern local sandboxed command execution -- and only that. They control which files local commands can read or write, whether those writes persist, and which outbound destinations are reachable through the proxy. They do not govern app connectors, MCP servers, browser and computer-use surfaces, or Codex cloud environment settings. Each of those has its own controls. If you need to constrain what an MCP server can do, the permission profile is the wrong layer.
Enforcement is OS-backed, and Codex fails closed. The mechanism varies by platform -- Seatbelt on macOS, bubblewrap plus seccomp (Landlock fallback) on Linux and WSL, sandbox users with filesystem ACLs and firewall rules on elevated Windows, a weaker fallback on unelevated Windows. The constant across all of them: when the platform sandbox cannot enforce the selected policy, Codex refuses to run the command rather than silently running it unsandboxed. That refusal is the feature. Codex is supported locally on macOS, Linux, WSL, and native Windows.
How a Reader Uses This
Pattern 1: Lock Secrets Out of an Otherwise-Writable Workspace
A developer who wants Codex to freely edit a repo but never read credentials:
- Set
default_permissions = ":workspace"so writes are scoped to workspace roots. - Add a custom profile that
extends:workspaceand adds"**/*.env" = "deny"under:workspace_roots, withglob_scan_max_depthset. - Enable network only for the domains the build actually needs (
"**.github.com" = "allow"), leaving the default block in place for everything else.
Pattern 2: Org-Wide Fail-Closed Baseline
A platform or security team standardizing Codex across an enterprise:
- Define the approved profiles centrally and list them in
allowed_permission_profilesin managedrequirements.toml. - Omit
:danger-full-accessfrom the list so it is denied org-wide by default. - Roll out on Codex 0.138.0+, and rely on fail-closed semantics: any future profile is unavailable until explicitly vetted and added.
When to Reach for a Profile vs Another Control
| You want to constrain... | Permission profile | Other control |
|---|---|---|
| Local command filesystem access | Yes | -- |
| Local command outbound network | Yes | -- |
| What an MCP server can do | No | MCP server controls |
| Signed-in browser actions | No | Computer Use / Chrome extension settings |
| Cloud environment behavior | No | Codex cloud environment settings |
| Non-interactive automation identity | No | Programmatic access tokens |
Why This Matters
Coarse sandbox modes forced a blunt choice: read-only, workspace-write, or full access. Permission profiles turn that into a composable, OS-enforced policy you can tune per task and inherit across config layers -- and, for enterprises, lock down with a fail-closed allowlist. The **/*.env = deny example is the tell: the design goal is least privilege that survives broad grants, so a writable workspace doesn't implicitly mean a readable secrets file.
The honest framing is the one OpenAI uses: this is beta, it may change, and it covers local command execution rather than every Codex surface. Treat it as the strongest available lever for the local sandbox, not a single switch that secures the whole agent.
FAQ
See the structured FAQ in the schema header for question-level details: what permission profiles are, the three built-ins, whether they compose with old sandbox settings, how fail-closed admin allowlists work, and what profiles do not control.
Sources
- Codex Permissions docs (beta): https://developers.openai.com/codex/permissions
- Thomas Sottiaux (OpenAI) announcement: https://x.com/thsottiaux/status/2071636285807059315
Read next
Keep building the workspace playbookCodex Hooks and Programmatic Access Tokens: How OpenAI Is Making Codex Easier to Automate Around Your Code
OpenAI is positioning Codex as an automatable platform. Hooks let you inject scripts at key points in the agent loop -- validators, secret scanning, conversation logging, per-repo behavior. Programmatic access tokens give Business and Enterprise teams scoped credentials they can use in CI, release jobs, and internal automations, created from the ChatGPT admin console with finite expirations and revocation. Both are live in the official Codex developer docs.
Codex Chrome Extension: How Codex Drives a Signed-In Browser for LinkedIn, Salesforce, Gmail, and Internal Tools
OpenAI's Codex Chrome extension lets the agent use Chrome for browser tasks that need signed-in state -- LinkedIn, Salesforce, Gmail, internal tools. Available in the Codex app in all regions except EU and UK at launch. Setup is Codex > Plugins > add Chrome > install extension > approve permissions. Invoke with @Chrome. By default Codex asks before each new website; allowlist/blocklist and elevated-risk options live in Computer Use settings.
Codex CLI vs Claude Code vs Cursor: 2026 Architecture Deep-Dive (Sandboxing, Context, Plugins, Scheduling)
Codex CLI, Claude Code, and Cursor all reach for the same outcome -- an AI agent that ships code -- with three different architectures. Codex enforces safety at the OS kernel layer. Claude Code uses application-layer hooks for programmable governance. Cursor builds the agent into a visual IDE with a marketplace of plugins. The right one depends less on which model you prefer and more on which architecture matches your security posture, your composition needs, and your team shape.
Frequently Asked Questions
What are Codex permission profiles?
A permission profile is a named, reusable policy that combines filesystem rules (read/write/deny) with network rules to set least-privilege boundaries for the local commands Codex runs on your behalf. Profiles replace the older sandbox_mode plus sandbox_workspace_write combination when you want one reusable definition of filesystem and network behavior. The feature is in beta and under active development.
What built-in profiles ship with Codex?
Three: ':read-only' blocks local modifications, ':workspace' permits writes within active workspace roots and the system temp directory, and ':danger-full-access' removes local sandbox restrictions. You set 'default_permissions' to one of these or to a custom profile defined under [permissions.<name>]. You can extend ':read-only', ':workspace', or another named profile, but you cannot extend ':danger-full-access'.
Do permission profiles compose with the old sandbox settings?
No. Profiles do not compose with sandbox_mode and sandbox_workspace_write. Configure either default_permissions plus [permissions] or the older sandbox settings -- not both. The one exception is enterprise managed allowed_permission_profiles, which overrides older sandbox settings entirely.
How do the fail-closed admin allowlists work?
Enterprise admins define profiles and restrict which ones users may select via managed allowed_permission_profiles in requirements.toml. Once that list is present, any omitted profile is denied -- including omitted built-ins and any future profiles. That is the fail-closed behavior: new or unlisted profiles default to unavailable rather than allowed. Managed allowed_permission_profiles requires Codex 0.138.0 or later.
What do permission profiles not control?
Profiles govern local sandboxed command execution only. They do not govern app connectors, MCP servers, browser and computer-use surfaces, or Codex cloud environment settings -- those use their own controls. If the platform sandbox cannot enforce a selected policy, Codex refuses to run the command rather than silently running it unsandboxed.