Repository navigation
Labels
CLIIssues related to the Codex CLIIssues related to the Codex CLIbugSomething isn't workingSomething isn't workingsandboxIssues related to permissions or sandboxingIssues related to permissions or sandboxing
Description
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_rootsAlso just want to say thank you for adding a bubblewrap-based sandbox!! Landlock was causing some headaches
Metadata
Metadata
Assignees
Labels
CLIIssues related to the Codex CLIIssues related to the Codex CLIbugSomething isn't workingSomething isn't workingsandboxIssues related to permissions or sandboxingIssues related to permissions or sandboxing
Activity
github-actions commentedon Mar 14, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
fix(sandbox): resolve symlinks in bwrap writable roots before bind-mo…
fix: fix symlinked writable roots in sandbox policies (#14674)
Merge upstream/main into fork main (#9)
fix(permissions): fix symlinked writable roots in sandbox permissions (…
fix: fix symlinked writable roots in sandbox policies (openai#14674)
fix(permissions): fix symlinked writable roots in sandbox permissions (…