Skip to content

Cross-Platform Sandbox

源码版本rust-v0.145.0

codex isolates command execution into platform-native sandboxes: macOS uses sandbox-exec (seatbelt), Linux uses bubblewrap + seccomp, Windows uses restricted tokens. The sandboxing crate provides the unified abstraction; linux-sandbox/, bwrap/, windows-sandbox-rs/, process-hardening/ are the per-platform implementations. core computes the SandboxType before each exec, then hands it to SandboxManager::transform to build the actual argv to spawn.

Responsibilities

  1. Decide whether to enable the sandbox and which backend by PermissionProfile: codex-rs/sandboxing/src/manager.rs:273-319
  2. On macOS, build the sandbox-exec seatbelt policy and argv: codex-rs/sandboxing/src/seatbelt.rs:21-30
  3. On Linux, go through the codex-linux-sandbox helper: first no_new_privs + seccomp, then exec bubblewrap: codex-rs/linux-sandbox/src/lib.rs:1-30
  4. On Windows, isolate filesystem and network via restricted token / elevated backend: codex-rs/windows-sandbox-rs/src/lib.rs:13-50
  5. Process-level hardening before main (disable core dumps, refuse ptrace, clear LD_PRELOAD / DYLD_*): codex-rs/process-hardening/src/lib.rs:12-25

Design motivation

Why not just trust execpolicy's gating? Because the model can construct arbitrary shells and rule engines always have edge cases. Forcing every command into an OS-native sandbox is the "even if the model bypasses everything, the kernel layer still stops it" last line of defense. SandboxablePreference::Auto lets strategic profiles like workspace-write / read-only enable the sandbox, while the full-access profile degrades directly to SandboxType::None, avoiding needless process wrapping.

Each platform has a different backend because there is no unified cross-platform sandbox primitive: macOS's seatbelt is declarative .sbpl, Linux's bubblewrap is user namespace + bind mount, Windows's restricted token is token + ACL. The SandboxType enum unifies these three backends with None under the same label, so core / exec-server only see the label and don't care about platform details.

Key files

SandboxType unifies the three platform backends with "no sandbox" into one label; core only sees the label.

rust
pub enum SandboxType {
    None,
    MacosSeatbelt,
    LinuxSeccomp,
    WindowsRestrictedToken,
}

In select_initial, first decide whether to sandbox via should_sandbox, then ask the platform what backend it can provide:

rust
pub fn select_initial(
    &self,
    file_system_policy: &FileSystemSandboxPolicy,
    network_policy: NetworkSandboxPolicy,
    pref: SandboxablePreference,
    windows_sandbox_level: WindowsSandboxLevel,
    has_managed_network_requirements: bool,
) -> SandboxType {
    if self.should_sandbox(
        file_system_policy,
        network_policy,
        pref,
        has_managed_network_requirements,
    ) {
        get_platform_sandbox(windows_sandbox_level != WindowsSandboxLevel::Disabled)
            .unwrap_or(SandboxType::None)
    } else {
        SandboxType::None
    }
}

The Linux launcher picks between system bwrap and bundled bwrap, and panics if neither is found — when bubblewrap is unavailable the whole Linux sandbox chain is dead.

rust
pub(crate) fn exec_bwrap(argv: Vec<String>, preserved_files: Vec<File>) -> ! {
    match preferred_bwrap_launcher() {
        BubblewrapLauncher::System(launcher) => {
            exec_system_bwrap(&launcher.program, argv, preserved_files)
        }
        BubblewrapLauncher::Bundled(launcher) => launcher.exec(argv, preserved_files),
        BubblewrapLauncher::Unavailable => {
            panic!(
                "bubblewrap is unavailable: no system bwrap was found on PATH and no bundled \
                 codex-resources/bwrap binary was found next to the Codex executable"
            )
        }
    }
}

Data flow

Boundaries and failures

Summary

SandboxManager is codex's unified cross-platform sandbox entry: it translates PermissionProfile into SandboxType, then into a wrapped argv. Platform backends isolate separately but all derive from the same FileSystemSandboxPolicy / NetworkSandboxPolicy. To trace "why was this command rejected", see command classification execpolicy and command execution exec-server.