From 8179312ff5b39ea879bceb7eaed8187002a5fa04 Mon Sep 17 00:00:00 2001 From: Tiffany Citra Date: Wed, 21 Jan 2026 10:43:10 -0800 Subject: [PATCH] fix: Fix tilde expansion to avoid absolute-path escape (#9621) ### Motivation - Prevent inputs like `~//` or `~///etc` from expanding to arbitrary absolute paths (e.g. `/`) because `Path::join` discards the left side when the right side is absolute, which could allow config values to escape `HOME` and broaden writable roots. ### Description - In `codex-rs/utils/absolute-path/src/lib.rs` update `maybe_expand_home_directory` to trim leading separators from the suffix and return `home` when the remainder is empty so tilde expansion stays rooted under `HOME`. - Add a non-Windows unit test `home_directory_double_slash_on_non_windows_is_expanded_in_deserialization` that validates `"~//code"` expands to `home.join("code")`. ### Testing - Ran `just fmt` successfully. - Ran `just fix -p codex-utils-absolute-path` (Clippy autofix) successfully. - Ran `cargo test -p codex-utils-absolute-path` and all tests passed. ------ [Codex Task](https://chatgpt.com/codex/tasks/task_i_697007481cac832dbeb1ee144d1e4cbe) --- codex-rs/utils/absolute-path/src/lib.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/codex-rs/utils/absolute-path/src/lib.rs b/codex-rs/utils/absolute-path/src/lib.rs index 966b061bf..28b4f39a5 100644 --- a/codex-rs/utils/absolute-path/src/lib.rs +++ b/codex-rs/utils/absolute-path/src/lib.rs @@ -33,6 +33,10 @@ impl AbsolutePathBuf { return home; } if let Some(rest) = path_str.strip_prefix("~/") { + let rest = rest.trim_start_matches('/'); + if rest.is_empty() { + return home; + } return home.join(rest); } } @@ -253,6 +257,20 @@ mod tests { assert_eq!(abs_path_buf.as_path(), home.join("code").as_path()); } + #[cfg(not(target_os = "windows"))] + #[test] + fn home_directory_double_slash_on_non_windows_is_expanded_in_deserialization() { + let Some(home) = home_dir() else { + return; + }; + let temp_dir = tempdir().expect("base dir"); + let abs_path_buf = { + let _guard = AbsolutePathBufGuard::new(temp_dir.path()); + serde_json::from_str::("\"~//code\"").expect("failed to deserialize") + }; + assert_eq!(abs_path_buf.as_path(), home.join("code").as_path()); + } + #[cfg(target_os = "windows")] #[test] fn home_directory_on_windows_is_not_expanded_in_deserialization() {