From f1aac1e885f676a1129f2da0c46a3dba86392fc6 Mon Sep 17 00:00:00 2001 From: zm-oai Date: Fri, 4 Sep 2026 18:51:33 +0000 Subject: [PATCH] Preserve SystemRoot for Windows sandbox wrapper setup (#42833) ## Why `ShellExecuteExW` needs `SystemRoot` to elevate the Windows sandbox setup helper. ## What changed Add `SYSTEMROOT` to the environment variables copied from the host for wrapper setup. Keep the serialized inner command environment unchanged so the host value is available only to the wrapper. ## Testing Extend Windows sandbox manager tests to cover case-insensitive replacement of `SystemRoot` and verify that it is excluded from the inner command environment. GitOrigin-RevId: c69f9f92665e97a178e2de488fbb9fd6b7ff7ac6 --- codex-rs/sandboxing/src/manager.rs | 7 ++++++- codex-rs/sandboxing/src/manager_tests.rs | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/codex-rs/sandboxing/src/manager.rs b/codex-rs/sandboxing/src/manager.rs index 530c2cb831..b633e8f779 100644 --- a/codex-rs/sandboxing/src/manager.rs +++ b/codex-rs/sandboxing/src/manager.rs @@ -31,7 +31,12 @@ use std::io; use std::path::Path; #[cfg(target_os = "windows")] -const WINDOWS_SANDBOX_WRAPPER_SETUP_ENV_ALLOWLIST: &[&str] = &["USERNAME", "USERPROFILE"]; +const WINDOWS_SANDBOX_WRAPPER_SETUP_ENV_ALLOWLIST: &[&str] = &[ + "USERNAME", + "USERPROFILE", + // ShellExecuteExW needs SystemRoot to elevate the setup helper. + "SYSTEMROOT", +]; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum SandboxType { diff --git a/codex-rs/sandboxing/src/manager_tests.rs b/codex-rs/sandboxing/src/manager_tests.rs index 11341b21f8..8954f11d48 100644 --- a/codex-rs/sandboxing/src/manager_tests.rs +++ b/codex-rs/sandboxing/src/manager_tests.rs @@ -490,11 +490,12 @@ fn transform_linux_seccomp_uses_helper_alias_when_launcher_is_not_helper_path() #[cfg(target_os = "windows")] #[test] -fn transform_for_direct_spawn_windows_preserves_only_wrapper_setup_identity() { +fn transform_for_direct_spawn_windows_preserves_only_wrapper_setup_environment() { let mut env = HashMap::from([ ("Path".to_string(), r"C:\Windows\System32".to_string()), ("username".to_string(), "wrong-user".to_string()), ("UserProfile".to_string(), r"C:\wrong".to_string()), + ("SYSTEMROOT".to_string(), r"C:\wrong".to_string()), ]); super::add_windows_sandbox_wrapper_setup_env_from_vars( @@ -502,7 +503,9 @@ fn transform_for_direct_spawn_windows_preserves_only_wrapper_setup_identity() { [ ("USERNAME", "alice"), ("USERPROFILE", r"C:\Users\alice"), + ("SystemRoot", r"C:\Windows"), ("OPENAI_API_KEY", "secret"), + ("HTTP_PROXY", "http://127.0.0.1:7890"), ] .map(|(key, value)| { ( @@ -518,6 +521,7 @@ fn transform_for_direct_spawn_windows_preserves_only_wrapper_setup_identity() { ("Path".to_string(), r"C:\Windows\System32".to_string()), ("USERNAME".to_string(), "alice".to_string()), ("USERPROFILE".to_string(), r"C:\Users\alice".to_string()), + ("SystemRoot".to_string(), r"C:\Windows".to_string()), ]) ); } @@ -596,6 +600,17 @@ fn transform_for_direct_spawn_windows_materializes_inner_helper() { ) .expect("transform for direct spawn"); + let inner_env_json = exec_request + .command + .windows(2) + .find(|args| args[0] == "--env-json") + .expect("inner command environment"); + assert_eq!( + serde_json::from_str::>(&inner_env_json[1]) + .expect("decode inner command environment"), + HashMap::from([("Path".to_string(), r"C:\Windows\System32".to_string())]) + ); + let separator_index = exec_request .command .iter()