From 9b370f458e9688e3fd360d9de093b1093b15fafb Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 23 Oct 2026 06:10:49 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20Fi?= =?UTF-8?q?x=20command=20obfuscation=20bypass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Validated command tokens instead of raw string to catch quoted obfuscations like `npm run "s"udo`. Co-authored-by: bobdivx <6737167+bobdivx@users.noreply.github.com> --- crates/agent/src/tools/workdir_cmd.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/crates/agent/src/tools/workdir_cmd.rs b/crates/agent/src/tools/workdir_cmd.rs index 77426cbf8..46a5ff54a 100644 --- a/crates/agent/src/tools/workdir_cmd.rs +++ b/crates/agent/src/tools/workdir_cmd.rs @@ -101,16 +101,17 @@ fn validate_command(raw: &str) -> std::result::Result, String> { if cmd.len() > 400 { return Err("command trop longue (max 400)".into()); } - let lower = cmd.to_ascii_lowercase(); + let parts = shell_words_split(cmd); + if parts.is_empty() { + return Err("command invalide".into()); + } + let joined = parts.join(" "); + let lower = joined.to_ascii_lowercase(); for bad in BLOCKED_TOKENS { if lower.contains(bad) { return Err(format!("token interdit dans la commande : {bad}")); } } - let parts = shell_words_split(cmd); - if parts.is_empty() { - return Err("command invalide".into()); - } let bin = parts[0].as_str(); let bin_base = Path::new(bin) .file_name() @@ -348,6 +349,12 @@ mod tests { fn blocks_curl() { assert!(validate_command("curl https://x").is_err()); } + + #[test] + fn blocks_obfuscated_commands() { + assert!(validate_command("npm run \"s\"udo").is_err()); + assert!(validate_command("cat \"..\"/\"..\"/etc/passwd").is_err()); + } } /// Tue le groupe de processus (npm et ses scripts enfants) si le futur est abandonné.