ExGuardian

Guide · Codex CLI, IDE extension and desktop app · Checked against the docs on 29 October 2026

Codex sandbox, explained from the config file.

Short answer. Codex runs every command it starts inside an operating-system sandbox: Seatbelt on macOS, bubblewrap and seccomp on Linux and WSL2, MXC or a sandbox user on Windows. sandbox_mode sets the boundary and approval_policy sets when Codex stops to ask. In a git repository the default is workspace-write with on-request approvals and no network. Most of the risk comes from three switches: --yolo, network without a domain allowlist, and secrets left in the environment.

How does the Codex sandbox work?

The sandbox applies to local work in the Codex CLI, the IDE extension and the ChatGPT desktop app. It wraps each shell command Codex runs and everything that command spawns, so git, npm or a test runner inherit the same limits. Two settings work together: the sandbox decides what a command can technically touch, and the approval policy decides when Codex must pause and ask before going further.

PlatformMechanismSetupWatch for
macOSSeatbelt, the sandbox framework built into macOSNothing to install.codex sandbox --log-denials prints what the sandbox refused after a test command.
Linux, WSL2bubblewrap for the filesystem view, then no_new_privs and a seccomp filter; network cut with a separate namespacesudo apt install bubblewrap or sudo dnf install bubblewrap. Codex falls back to a bundled helper that needs unprivileged user namespaces.Ubuntu 24.04 may block user namespaces through AppArmor. WSL1 is not supported: sandboxed commands are rejected.
Windows (PowerShell)MXC native process isolation, with elevated (dedicated sandbox users, firewall rules) and unelevated (restricted token) as legacy fallbacksMXC needs Windows 11 24H2 build 26100.9278 or 25H2 build 26200.9278. Opt in with prefer_mxc = true under [features].unelevated has weaker network isolation and no denied read paths.

On Linux the design is worth knowing in detail because it explains what leaks. The helper mounts the whole filesystem read-only (--ro-bind / /), binds each writable root on top, then re-applies .git, the resolved gitdir: target and .codex as read-only. It always creates a new user namespace and, by default, a PID namespace. With network restricted it adds --unshare-net, and the seccomp filter blocks network syscalls and io_uring, which could otherwise bypass the socket rules. Codex prints a warning at startup when bwrap is missing or user namespaces fail. It is a warning, not a stop, so read your startup output.

To see the boundary from outside the agent, run a command through it yourself with codex sandbox, for example codex sandbox -- touch ../outside.txt. The write should fail. On macOS, --log-denials lists every refusal.

Which sandbox mode should you use?

sandbox_modeFilesNetworkUse it for
read-onlyReads files. No edits and no commands without approval.OffReviewing an unknown repository, CI jobs that only analyse.
workspace-writeReads, edits inside the workspace and runs routine commands there. Protected paths stay read-only.Off by defaultDaily local work. The default in a version-controlled folder.
danger-full-accessAny file your account can reach.OnA throwaway VM or container that is itself the boundary.

Codex picks the mode from the folder. A version-controlled folder starts in Auto (workspace-write plus on-request). A folder without version control starts read-only, and Codex can also stay read-only until you trust the directory in onboarding or with /permissions. The desktop app and IDE name the same choices Ask for approval, Approve for me (eligible prompts go to a reviewer agent) and Full access.

config.tomlthe three keys that decide most behaviour
# ~/.codex/config.toml
sandbox_mode = "workspace-write"     # read-only | workspace-write | danger-full-access
approval_policy = "on-request"       # on-request | never | { granular = { ... } }
web_search = "cached"                # disabled | cached | indexed | live
PresetFlags
Auto (default in a git repository)--sandbox workspace-write --ask-for-approval on-request
Read-only browsing--sandbox read-only --ask-for-approval on-request
Read-only CI job--sandbox read-only --ask-for-approval never
Auto-review--sandbox workspace-write --ask-for-approval on-request -c approvals_reviewer=auto_review
Dangerous full access--dangerously-bypass-approvals-and-sandbox (alias --yolo)

If a tool needs one more folder, add it with sandbox_workspace_write.writable_roots rather than switching to full access. For a second project, OpenAI's guidance is to open a separate project or worktree instead of widening the first one.

What do the approval policies change?

approvals_reviewer = "auto_review" sends eligible prompts to a reviewer model instead of you. It only sees actions that already needed approval, it denies critical-risk actions, and it fails closed when its own prompt or parse fails. It does not move the sandbox boundary, and admins can forbid it with allowed_approvals_reviewers.

What stays protected in workspace-write?

Inside every writable root, these paths stay read-only recursively, so a prompt-injected command cannot rewrite your history, your agent config or your cloud profile:

Two writable areas are easy to forget: /tmp and $TMPDIR. Remove them with exclude_slash_tmp = true and exclude_tmpdir_env_var = true under [sandbox_workspace_write] if your tools do not need them. And note what the list covers: .aws is write-protected, not hidden. Reads are a separate question, covered below.

How do you turn on network access safely?

Network is off in workspace-write. Turning it on with network_access = true opens every destination. Pair it with the network proxy, which applies domain rules: exact hosts match only themselves, *.example.com matches subdomains but not the apex, **.example.com matches both, and a deny beats an allow.

config.tomlnetwork on, package registries only
[sandbox_workspace_write]
network_access = true

[features.network_proxy]
enabled = true
domains = { "registry.npmjs.org" = "allow", "pypi.org" = "allow", "files.pythonhosted.org" = "allow" }

The same rules can live in a named permissions profile, which keeps one profile per kind of task. The proxy feature still has to be on for the profile's domain rules to apply.

config.tomlpermissions profile variant
default_permissions = "project-edit"

[features]
network_proxy = true

[permissions.project-edit]
extends = ":workspace"

[permissions.project-edit.network]
enabled = true

[permissions.project-edit.network.domains]
"registry.npmjs.org" = "allow"

How does the Codex sandbox work on Windows?

Native Windows has three implementations, and the one you get changes what is enforced:

ImplementationHow it isolatesLimits
mxcNative process isolation. No admin setup, extra accounts or firewall rules.Needs Windows 11 24H2 or 25H2 at build .9278. Child processes stop when the foreground command exits, so detached dev servers do not survive.
elevatedAdmin-approved setup creates lower-privilege sandbox users, filesystem boundaries, firewall rules and local policy.Some enterprise devices block the setup. Error 1385 means a logon right is missing.
unelevatedA restricted token from your own user, ACL boundaries, environment-level offline controls.Weaker network isolation, no denied read paths. A fallback only.

Test MXC on one command with codex -c windows.sandbox=mxc sandbox ... (Codex CLI 0.162.0 or later): MXC_OK and exit code 0 mean it works. Admins pin the choice in requirements.toml, for example allowed_sandbox_implementations = ["elevated"] under [windows] to forbid the unelevated fallback. Inside WSL2, Codex uses the Linux sandbox described above. If Codex warns that a folder is writable by Everyone, fix the ACL: the sandbox cannot fully protect a folder that is already open to every account.

What has escaped the Codex sandbox before?

The openai/codex advisory page lists one advisory, and NVD lists a second CVE reported outside it. Both teach something about where the boundary sits.

CVEWhat happenedFixed in
CVE-2025-59532Codex could treat a working directory generated by the model as the sandbox's writable root, which allowed file writes and command execution outside the workspace. The network restriction was not affected. CVSS 4.0 score 8.6, published 19 September 2025.npm 0.39.0, IDE extension 0.4.12
CVE-2025-61260A repository's .env could point CODEX_HOME at a project-local .codex/config.toml, whose MCP server entry ran its command as soon as the user started codex in that folder, without confirmation. NVD lists CVSS 3.1 at 9.8.Versions after 0.23.0

The first one shows that the sandbox is only as good as the inputs used to build it. The second shows a route around it entirely: configuration read from the repository started a process before any sandboxed command ran. Keep Codex current (0.165.0 on npm when we checked), and treat a repository you did not write as untrusted configuration as well as untrusted code.

What does the sandbox not cover?

What does a hardened Codex config look like?

A starting point for a developer machine. It keeps the default boundary, closes the two writable temp areas you rarely need, strips secrets from command environments and marks third-party repositories untrusted.

~/.codex/config.tomlhardened local defaults
sandbox_mode = "workspace-write"
approval_policy = "on-request"
web_search = "cached"

[sandbox_workspace_write]
network_access = false
exclude_slash_tmp = true

[shell_environment_policy]
inherit = "core"                  # all | core | none
ignore_default_excludes = false   # strip variables named *KEY*, *SECRET*, *TOKEN*

# A repository you did not write: no project .codex/ config, hooks or rules,
# and commands need approval unless a rule allows them.
[projects."/home/me/src/third-party-repo"]
trust_level = "untrusted"

For a team, set the same choices centrally. Managed configuration takes precedence over the user's file and exposes allow-lists such as allowed_approval_policies, allowed_web_search_modes and allowed_approvals_reviewers, so a developer cannot switch to never plus full access on a company laptop. Turn on OpenTelemetry export (off by default) with log_user_prompt = false if you want an audit trail without storing prompts.

Then check it from outside the agent: run codex sandbox with a write outside the workspace, a curl to a host that is not allowed, and an env | grep -i token. All three should come back empty or refused.

Codex sandbox questions.

What is the Codex sandbox?

It is the operating-system boundary around every command Codex runs and every process those commands start: Seatbelt on macOS, bubblewrap plus seccomp on Linux and WSL2, MXC or a dedicated sandbox user on Windows. The sandbox_mode setting decides what the boundary allows; approval_policy decides when Codex stops to ask you.

Does Codex have network access by default?

No. In workspace-write mode, outbound network is off until you set network_access = true under [sandbox_workspace_write]. Web search is a separate tool and defaults to cached, an OpenAI-maintained index, which becomes live under --yolo.

How do I disable the Codex sandbox?

Use --sandbox danger-full-access, or --dangerously-bypass-approvals-and-sandbox (alias --yolo), which also removes approvals. OpenAI's documentation does not recommend it. If a tool needs one more folder or one host, add a writable root or a proxy domain rule instead and keep the sandbox.

Can Codex read my SSH keys or cloud credentials?

The sandbox limits writes far more than reads: on Linux the whole filesystem is mounted read-only, so it stays readable. In workspace-write, .aws inside a writable root is write-protected, not hidden. To keep files unreadable, use a permissions profile that marks the path none, and keep secrets out of the environment with shell_environment_policy.

Is the Codex sandbox safe for untrusted repositories?

Two published CVEs say update first: CVE-2025-59532 let a model-chosen working directory become the writable root (fixed in 0.39.0), and CVE-2025-61260 let a repository's .env and .codex/config.toml start an MCP server command without confirmation (fixed after 0.23.0). Then mark the project trust_level = "untrusted" so its project config is skipped.

Sources