Documents
Permission and Security Architecture
Permission and Security Architecture
Type
Topic
Status
Published
Created
May 27, 2026
Updated
May 27, 2026
Template

Permission and Security Architecture#

Codex enforces security boundaries on agent shell commands through a layered permission system. There are two coexisting models:

  • PermissionProfile — the canonical, actively developed model
  • SandboxPolicy — the legacy model, now derived from PermissionProfile for backward compatibility

The architecture has three layers:

  1. Wire/protocol typescodex-rs/protocol/src/ and codex-rs/app-server-protocol/
  2. Core resolution logiccodex-rs/core/src/config/resolved_permission_profile.rs resolves named/built-in/legacy profiles into a PermissionProfileSnapshot
  3. Platform backends — Landlock and Bubblewrap on Linux (codex-rs/linux-sandbox/), Windows Sandbox (codex-rs/windows-sandbox-rs/)

At session startup, SessionConfiguration calls permission_profile() to obtain the active PermissionProfile, then derives a SandboxPolicy from it via to_legacy_sandbox_policy() — with a fallback to codex_sandboxing::compatibility_sandbox_policy_for_permission_profile() when direct conversion is not possible.

PermissionProfile#

PermissionProfile is defined in codex-rs/protocol/src/models.rs with three variants that encode who owns sandbox enforcement:

VariantMeaning
Managed { file_system, network }Codex owns sandbox construction end-to-end
DisabledNo outer sandbox is applied
External { network }Filesystem isolation is the caller's responsibility; Codex controls only network

The file_system field of Managed is a ManagedFileSystemPermissions enum with two sub-variants:

  • Restricted { entries, glob_scan_max_depth } — sandbox enforced via an explicit Vec<FileSystemSandboxEntry>
  • Unrestricted — all filesystem access allowed, but Codex still owns the sandbox process

Three built-in named profiles are provided as string constants :

  • :read-only
  • :workspace
  • :danger-full-access

The network axis is controlled separately by NetworkSandboxPolicy, which defaults to Restricted and can be set to Enabled.

Legacy SandboxPolicy (Migration In Progress)#

SandboxPolicy is defined in codex-rs/protocol/src/protocol.rs and represents the original security model. Its four variants map roughly onto the new model:

VariantEquivalent
DangerFullAccessPermissionProfile::Managed { Unrestricted }
ReadOnlyPermissionProfile::Managed { Restricted, read-only entries }
ExternalSandboxPermissionProfile::External
WorkspaceWritePermissionProfile::Managed { Restricted, workspace entries }

Migration path. PermissionProfile provides bidirectional conversion :

New code should target PermissionProfile directly. SandboxPolicy is preserved as a compatibility shim.

Core Types: FileSystemSandboxPolicy and Profile Resolution#

FileSystemSandboxPolicy#

FileSystemSandboxPolicy is the operational model consumed by platform sandbox backends. It is obtained by calling PermissionProfile::to_runtime_permissions(), which returns a (FileSystemSandboxPolicy, NetworkSandboxPolicy) tuple.

Key sub-types:

Protected metadata directories (.git, .agents, .codex) are automatically carved out as read-only from any writable root .

Key query methods on FileSystemSandboxPolicy:

Profile Resolution#

ResolvedPermissionProfile in codex-rs/core/src/config/resolved_permission_profile.rs captures the resolution state:

ResolvedPermissionProfile
  ├── Legacy(LegacyPermissionProfile)
  ├── BuiltIn(BuiltInPermissionProfile) — :read-only, :workspace, :danger-full-access
  └── Named(NamedPermissionProfile) — user-defined in config.toml

A PermissionProfileSnapshot is the trusted, durable form used at runtime, carrying the resolved profile plus workspace root metadata.

Platform Sandbox Backends#

Both Linux backends are given a FileSystemSandboxPolicy extracted from PermissionProfile via to_runtime_permissions().

Linux: Landlock#

apply_permission_profile_to_current_thread() in codex-rs/linux-sandbox/src/landlock.rs:

  1. Calls permission_profile.to_runtime_permissions() to get FileSystemSandboxPolicy
  2. Checks has_full_disk_write_access() and has_full_disk_read_access() to short-circuit when no restriction is needed
  3. Calls get_writable_roots_with_cwd(cwd) to enumerate paths for Landlock rules

Linux: Bubblewrap (bwrap)#

create_bwrap_command_args() in codex-rs/linux-sandbox/src/bwrap.rs:

  1. Accepts a &FileSystemSandboxPolicy directly
  2. Calls get_unreadable_globs_with_cwd() to identify paths to mask via --tmpfs/--dir binds
  3. Checks has_full_disk_write_access() to decide whether bwrap wrapping is needed at all
  4. Passes the policy to create_filesystem_args() for detailed mount construction

Windows#

Windows-specific sandbox logic lives in codex-rs/windows-sandbox-rs/src/ with path resolution in resolved_permissions.rs.

TOML Configuration and Inheritance#

Permission profiles are configured in config.toml under [permission_profiles.<name>]. The schema is defined in codex-rs/config/src/permissions_toml.rs:

[permission_profiles.my-profile]
description = "..."
extends = ":workspace" # inherit from a built-in or named profile
[permission_profiles.my-profile.filesystem.entries]
"/sensitive/**" = "deny"
"~/projects" = "write"
[permission_profiles.my-profile.network]
enabled = true

Key schema fields :

  • extends — profile inheritance; parent is merged before child overrides are applied; cycle detection is enforced
  • workspace_roots — override the set of workspace root directories
  • filesystem.entriesBTreeMap<path, access> where access is Read | Write | Deny, or a scoped sub-map
  • filesystem.glob_scan_max_depth — cap on glob expansion depth

Known regression (v0.132.0 / App 26.519.22136): A canonicalization change renamed the filesystem access value nonedeny. Existing config.toml files using none caused a hard parse failure that cascaded into broken chat, hooks, and MCP server loading . If upgrading from an older config, audit all = "none" entries and replace with = "deny".

V2 API Protocol Layer#

The app-server V2 protocol (codex-rs/app-server-protocol/src/protocol/v2/permissions.rs) exposes permission types to API clients with full bidirectional conversion to/from core types .

Key types:

The legacy SandboxPolicy enum is still accepted by the V2 layer with deprecation warnings and is converted to core types via to_core() .