Skip to content

bwrap sandbox bind fails with symlinked TMPDIR #14672

Description

@tomstitt

What version of Codex CLI is running?

main

What subscription do you have?

API User (Azure)

Which model were you using?

No response

What platform is your computer?

No response

What terminal emulator and version are you using (if applicable)?

No response

What issue are you seeing?

With the linux bwrap sandbox on systems where TMPDIR is a symlink, bwrap fails to actually bind TMPDIR when it's a writable root. This causes downstream errors when codex tries to do anything with TMPDIR resulting in (usually unnecessary) requests for elevated permissions.

What steps can reproduce the bug?

For example, mktemp fails because TMPDIR isn't actually bound in:

> codex sandbox linux --full-auto mktemp
bwrap: Can't mkdir {TMPDIR}: No such file or directory

What is the expected behavior?

With a patched codex, that resolves directories before --bind-ing, it works:

>  codex-patched sandbox linux --full-auto mktemp
{TMPDIR}/tmp.BzOpNFXRw7

Or, with TMPDIR as an absolute path which is probably most common, it works:

> TMPDIR={...} codex sandbox linux --full-auto mktemp
{...}/tmp.OPmu0IajVm

Additional information

Here's my patch:

diff --git a/codex-rs/linux-sandbox/src/bwrap.rs b/codex-rs/linux-sandbox/src/bwrap.rs
index e93bb80f1..2980717d5 100644
--- a/codex-rs/linux-sandbox/src/bwrap.rs
+++ b/codex-rs/linux-sandbox/src/bwrap.rs
@@ -11,6 +11,7 @@
 //! - bubblewrap used to construct the filesystem view before exec.
 use std::collections::BTreeSet;
 use std::collections::HashSet;
+use std::fs;
 use std::fs::File;
 use std::os::fd::AsRawFd;
 use std::path::Path;
@@ -300,7 +301,9 @@ fn create_filesystem_args(
     }

     for writable_root in &sorted_writable_roots {
-        let root = writable_root.root.as_path();
+        let relative_root = writable_root.root.as_path();
+        let real_root = fs::canonicalize(relative_root)?;
+        let root = real_root.as_path();
         // If a denied ancestor was already masked, recreate any missing mount
         // target parents before binding the narrower writable descendant.
         if let Some(masking_root) = unreadable_roots

Also just want to say thank you for adding a bubblewrap-based sandbox!! Landlock was causing some headaches

Activity

  1. added
    CLIIssues related to the Codex CLI
    sandboxIssues related to permissions or sandboxing
    on Mar 14, 2026
  2. github-actions commented on Mar 14, 2026

    @github-actions
    Contributor
  3. added a commit that references this issue on Mar 14, 2026
    b682ef8
  4. added a commit that references this issue on Apr 11, 2026
    b114781
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingsandboxIssues related to permissions or sandboxing

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions