From 3e56f3526e0402cdc97c40bb2427d62e4f4f40a1 Mon Sep 17 00:00:00 2001 From: Zhang Zihan <42645953+shentoumengxin@users.noreply.github.com> Date: Mon, 4 May 2026 15:18:16 +0800 Subject: [PATCH] fix(shell): validate cwd parameter against workspace boundary (#524) The shell tool's `cwd` / `working_dir` parameter was accepted raw without any workspace boundary check, unlike file tools which all go through `ToolContext::resolve_path()`. This allowed the AI model to execute shell commands from arbitrary directories outside the workspace. Reuse the existing `resolve_path()` validation so that: - Paths outside the workspace root are rejected with `PathEscape` - `trust_mode = true` still bypasses the check (consistent behavior) - `trusted_external_paths` entries are respected automatically - Default behavior (no cwd argument) remains unchanged Co-authored-by: Claude Opus 4.6 --- crates/tui/src/tools/shell.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/tui/src/tools/shell.rs b/crates/tui/src/tools/shell.rs index dfba4e30..7518c6d8 100644 --- a/crates/tui/src/tools/shell.rs +++ b/crates/tui/src/tools/shell.rs @@ -1560,11 +1560,18 @@ impl ToolSpec for ExecShellTool { } let policy_override = context.elevated_sandbox_policy.clone(); - let working_dir = input + let working_dir = match input .get("cwd") .or_else(|| input.get("working_dir")) .and_then(serde_json::Value::as_str) - .map(str::to_string); + { + Some(dir) => { + // Validate cwd against workspace boundary (same as file tools) + let resolved = context.resolve_path(dir)?; + Some(resolved.to_string_lossy().to_string()) + } + None => None, + }; let result = if interactive { let mut manager = context