Sandboxed apply_patch falls back to vendored bwrap because exec-server fs helper clears PATH
What version of Codex CLI is running?
0.120.0
What subscription do you have?
plus
Which model were you using?
gpt-5.4
What platform is your computer?
Ubuntu 24.04
What terminal emulator and version are you using (if applicable)?
wezterm
What issue are you seeing?
Summary
Sandboxed apply_patch can fall back to vendored bubblewrap when it runs through the exec-server filesystem sandbox helper. In environments where the system bwrap binary must be used, for example Ubuntu setups relying on AppArmor policy for /usr/bin/bwrap, this breaks sandboxed filesystem operations such as apply_patch.
What I observed
On my setup:
- sandboxed shell command execution works
apply_patchfails under sandbox- AppArmor logs show the helper going through the
codex-linux-sandboxpath instead of/usr/bin/bwrap - the helper then attempts to create a user namespace
- AppArmor rejects the namespace setup under the
unprivileged_usernsprofile
What steps can reproduce the bug?
If you run codex sandboxed with bwrap from system (/usr/bin/bwrap) and ask it to use apply_patch, it should fall back to using the vendored bwrap for that.
I can see it because it fails and asks for permission to run it outside the sandbox. And then in kern.log, i see that apparmor rejects the vendored tools attempt to create a user namespace.
I dont know how else you could see this, except if you change the code to throw an error when it tries to use the vendored one (which would be a nice setting to have. reject_vendored_bwrap=true).
What is the expected behavior?
Codex started under /usr/bin/bwrap, should keep using that.
Additional information
Root cause
The filesystem sandbox helper path introduced in d626dc3 launches the helper with an empty env map in SandboxCommand { env: HashMap::new(), ... }.
Later, spawn_command(...) in codex-rs/exec-server/src/fs_sandbox.rs does:
command.env_clear()command.envs(env)
So the helper process gets no PATH.
Later, Linux sandbox launcher selection in preferred_bwrap_launcher() uses find_system_bwrap_in_path(). Since PATH is missing in this helper process, system bwrap lookup fails and the code falls back to vendored bubblewrap.
Proposed solution
Preserve only PATH from the parent process when spawning the exec-server fs sandbox helper, while keeping the rest of the helper environment cleared.
diff --git a/codex-rs/exec-server/src/fs_sandbox.rs b/codex-rs/exec-server/src/fs_sandbox.rs
index 7b0ac25..3ed6c57 100644
--- a/codex-rs/exec-server/src/fs_sandbox.rs
+++ b/codex-rs/exec-server/src/fs_sandbox.rs
@@ -81,11 +81,14 @@ impl FileSystemSandboxRunner {
sandbox_context.windows_sandbox_level,
/*has_managed_network_requirements*/ false,
);
+ let path_env = std::env::var_os("PATH")
+ .map(|path| HashMap::from([("PATH".to_string(), path.to_string_lossy().into_owned())]))
+ .unwrap_or_default();
let command = SandboxCommand {
program: helper.as_path().as_os_str().to_owned(),
args: vec![CODEX_FS_HELPER_ARG1.to_string()],
cwd: cwd.clone(),
- env: HashMap::new(),
+ env: path_env,
additional_permissions: Some(
self.helper_permissions(sandbox_context.additional_permissions.as_ref()),
),
With that patch:
- sandboxed
apply_patchsucceeds again - writes outside the allowed sandbox roots still trigger the normal sandbox and approval behavior
- targeted tests pass:
cargo test -p codex-exec-servercargo test -p codex-linux-sandbox
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗