diff --git a/pkg/tools/shell.go b/pkg/tools/shell.go index d9430672f..f23504139 100644 --- a/pkg/tools/shell.go +++ b/pkg/tools/shell.go @@ -143,6 +143,29 @@ func (t *ExecTool) Execute(ctx context.Context, args map[string]interface{}) *To cwd := t.workingDir if wd, ok := args["working_dir"].(string); ok && wd != "" { + if t.restrictToWorkspace && t.workingDir != "" { + absWD, err := filepath.Abs(wd) + if err != nil { + return ErrorResult("invalid working_dir path") + } + absWorkspace, err := filepath.Abs(t.workingDir) + if err != nil { + return ErrorResult("failed to resolve workspace path") + } + if !isWithinWorkspace(absWD, absWorkspace) { + return ErrorResult("Command blocked by safety guard (working_dir outside workspace)") + } + // Also check symlink resolution + if resolved, err := filepath.EvalSymlinks(absWD); err == nil { + workspaceReal := absWorkspace + if r, err := filepath.EvalSymlinks(absWorkspace); err == nil { + workspaceReal = r + } + if !isWithinWorkspace(resolved, workspaceReal) { + return ErrorResult("Command blocked by safety guard (working_dir symlink resolves outside workspace)") + } + } + } cwd = wd }