core-agent-ide/codex-rs/linux-sandbox
iceweasel-oai 6b3d82daca
Use a private desktop for Windows sandbox instead of Winsta0\Default (#14400)
## Summary
- launch Windows sandboxed children on a private desktop instead of
`Winsta0\Default`
- make private desktop the default while keeping
`windows.sandbox_private_desktop=false` as the escape hatch
- centralize process launch through the shared
`create_process_as_user(...)` path
- scope the private desktop ACL to the launching logon SID

## Why
Today sandboxed Windows commands run on the visible shared desktop. That
leaves an avoidable same-desktop attack surface for window interaction,
spoofing, and related UI/input issues. This change moves sandboxed
commands onto a dedicated per-launch desktop by default so the sandbox
no longer shares `Winsta0\Default` with the user session.

The implementation stays conservative on security with no silent
fallback back to `Winsta0\Default`

If private-desktop setup fails on a machine, users can still opt out
explicitly with `windows.sandbox_private_desktop=false`.

## Validation
- `cargo build -p codex-cli`
- elevated-path `codex exec` desktop-name probe returned
`CodexSandboxDesktop-*`
- elevated-path `codex exec` smoke sweep for shell commands, nested
`pwsh`, jobs, and hidden `notepad` launch
- unelevated-path full private-desktop compatibility sweep via `codex
exec` with `-c windows.sandbox=unelevated`
2026-03-13 10:13:39 -07:00
..
src fix: reopen writable linux carveouts under denied parents (#14514) 2026-03-13 01:36:06 +00:00
tests Use a private desktop for Windows sandbox instead of Winsta0\Default (#14400) 2026-03-13 10:13:39 -07:00
BUILD.bazel build(linux-sandbox): always compile vendored bubblewrap on Linux; remove CODEX_BWRAP_ENABLE_FFI (#11498) 2026-02-11 21:30:41 -08:00
build.rs build(linux-sandbox): always compile vendored bubblewrap on Linux; remove CODEX_BWRAP_ENABLE_FFI (#11498) 2026-02-11 21:30:41 -08:00
Cargo.toml feat(linux-sandbox): implement proxy-only egress via TCP-UDS-TCP bridge (#11293) 2026-02-21 18:16:34 +00:00
config.h build(linux-sandbox): always compile vendored bubblewrap on Linux; remove CODEX_BWRAP_ENABLE_FFI (#11498) 2026-02-11 21:30:41 -08:00
README.md fix: reopen writable linux carveouts under denied parents (#14514) 2026-03-13 01:36:06 +00:00

codex-linux-sandbox

This crate is responsible for producing:

  • a codex-linux-sandbox standalone executable for Linux that is bundled with the Node.js version of the Codex CLI
  • a lib crate that exposes the business logic of the executable as run_main() so that
    • the codex-exec CLI can check if its arg0 is codex-linux-sandbox and, if so, execute as if it were codex-linux-sandbox
    • this should also be true of the codex multitool CLI

On Linux, the bubblewrap pipeline uses the vendored bubblewrap path compiled into this binary.

Current Behavior

  • Legacy SandboxPolicy / sandbox_mode configs remain supported.
  • Bubblewrap is the default filesystem sandbox pipeline and is standardized on the vendored path.
  • Legacy Landlock + mount protections remain available as an explicit legacy fallback path.
  • Set features.use_legacy_landlock = true (or CLI -c use_legacy_landlock=true) to force the legacy Landlock fallback.
  • The legacy Landlock fallback is used only when the split filesystem policy is sandbox-equivalent to the legacy model after cwd resolution.
  • Split-only filesystem policies that do not round-trip through the legacy SandboxPolicy model stay on bubblewrap so nested read-only or denied carveouts are preserved.
  • When the default bubblewrap pipeline is active, the helper applies PR_SET_NO_NEW_PRIVS and a seccomp network filter in-process.
  • When the default bubblewrap pipeline is active, the filesystem is read-only by default via --ro-bind / /.
  • When the default bubblewrap pipeline is active, writable roots are layered with --bind <root> <root>.
  • When the default bubblewrap pipeline is active, protected subpaths under writable roots (for example .git, resolved gitdir:, and .codex) are re-applied as read-only via --ro-bind.
  • When the default bubblewrap pipeline is active, overlapping split-policy entries are applied in path-specificity order so narrower writable children can reopen broader read-only or denied parents while narrower denied subpaths still win. For example, /repo = write, /repo/a = none, /repo/a/b = write keeps /repo writable, denies /repo/a, and reopens /repo/a/b as writable again.
  • When the default bubblewrap pipeline is active, symlink-in-path and non-existent protected paths inside writable roots are blocked by mounting /dev/null on the symlink or first missing component.
  • When the default bubblewrap pipeline is active, the helper explicitly isolates the user namespace via --unshare-user and the PID namespace via --unshare-pid.
  • When the default bubblewrap pipeline is active and network is restricted without proxy routing, the helper also isolates the network namespace via --unshare-net.
  • In managed proxy mode, the helper uses --unshare-net plus an internal TCP->UDS->TCP routing bridge so tool traffic reaches only configured proxy endpoints.
  • In managed proxy mode, after the bridge is live, seccomp blocks new AF_UNIX/socketpair creation for the user command.
  • When the default bubblewrap pipeline is active, it mounts a fresh /proc via --proc /proc by default, but you can skip this in restrictive container environments with --no-proc.

Notes

  • The CLI surface still uses legacy names like codex debug landlock.