From b9d2cfc1cc1a3e95043f95c915ae1bd74703e036 Mon Sep 17 00:00:00 2001 From: xaxadobit Date: Thu, 5 Mar 2026 21:59:36 -0300 Subject: [PATCH] fix: shell path validation false positives and agent config merge --- pkg/agent/instance.go | 4 +++- pkg/config/config.go | 15 ++++++++------- pkg/tools/shell.go | 8 ++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/pkg/agent/instance.go b/pkg/agent/instance.go index e14acf06d..cfc647e33 100644 --- a/pkg/agent/instance.go +++ b/pkg/agent/instance.go @@ -53,12 +53,14 @@ func NewAgentInstance( fallbacks := resolveAgentFallbacks(agentCfg, defaults) restrict := defaults.RestrictToWorkspace + if agentCfg != nil && agentCfg.RestrictToWorkspace != nil { + restrict = *agentCfg.RestrictToWorkspace + } readRestrict := restrict && !defaults.AllowReadOutsideWorkspace // Compile path whitelist patterns from config. allowReadPaths := compilePatterns(cfg.Tools.AllowReadPaths) allowWritePaths := compilePatterns(cfg.Tools.AllowWritePaths) - toolsRegistry := tools.NewToolRegistry() if cfg.Tools.IsToolEnabled("read_file") { diff --git a/pkg/config/config.go b/pkg/config/config.go index 7a0ec323c..b7ff9225f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -130,13 +130,14 @@ func (m AgentModelConfig) MarshalJSON() ([]byte, error) { } type AgentConfig struct { - ID string `json:"id"` - Default bool `json:"default,omitempty"` - Name string `json:"name,omitempty"` - Workspace string `json:"workspace,omitempty"` - Model *AgentModelConfig `json:"model,omitempty"` - Skills []string `json:"skills,omitempty"` - Subagents *SubagentsConfig `json:"subagents,omitempty"` + ID string `json:"id"` + Default bool `json:"default,omitempty"` + Name string `json:"name,omitempty"` + Workspace string `json:"workspace,omitempty"` + RestrictToWorkspace *bool `json:"restrict_to_workspace,omitempty"` + Model *AgentModelConfig `json:"model,omitempty"` + Skills []string `json:"skills,omitempty"` + Subagents *SubagentsConfig `json:"subagents,omitempty"` } type SubagentsConfig struct { diff --git a/pkg/tools/shell.go b/pkg/tools/shell.go index a0c83eb1e..500864064 100644 --- a/pkg/tools/shell.go +++ b/pkg/tools/shell.go @@ -339,10 +339,18 @@ func (t *ExecTool) guardCommand(command, cwd string) string { continue } + // Skip kernel pseudo-devices that are always safe. if safePaths[p] { continue } + // Only validate paths that actually exist on the filesystem. + // This prevents false positives from regex capturing non-path strings + // like escaped newlines (\n -> /n) or repo arguments (gh --repo owner/repo). + if _, err := os.Stat(p); os.IsNotExist(err) { + continue + } + rel, err := filepath.Rel(cwdPath, p) if err != nil { continue