fix(tool): guardCommand correctly skip URL paths in commands

When restrict_to_workspace is true, guardCommand now properly skips
URL paths like 'wttr.in/Beijing' in curl commands. Previously, these
were incorrectly matched as relative paths and blocked.

Issue: #1042
This commit is contained in:
liugangjian 2026-03-04 19:36:48 +08:00
parent f08fedc4a1
commit 8e8f7ced80

View file

@ -287,7 +287,50 @@ func (t *ExecTool) Execute(ctx context.Context, args map[string]any) *ToolResult
} }
} }
// isURLPath checks if the matched path is part of a URL rather than a file path.
// It detects patterns like "wttr.in/Beijing" or "http://example.com/path"
func isURLPath(command, matchedPath string) bool {
// Find the position of the matched path in the command
idx := strings.Index(command, matchedPath)
if idx == -1 {
return false
}
// Check what comes before the matched path
// If it's preceded by a dot (.) or //, it's likely a URL
if idx > 0 {
prefix := command[:idx]
trimmed := strings.TrimSpace(prefix)
// Check for URL patterns: domain.com/ or http:// or https://
if strings.HasSuffix(trimmed, ".") {
return true
}
if strings.HasSuffix(trimmed, "//") {
return true
}
// Check if the match starts with / and is preceded by a word character (domain)
if matchedPath[0] == '/' && idx > 0 {
before := command[idx-1]
if before == '.' || before == '/' {
return true
}
}
}
// Check if the matched path itself looks like a URL path component
// (contains query parameters or fragments)
if strings.Contains(matchedPath, "?") || strings.Contains(matchedPath, "#") || strings.Contains(matchedPath, "&") {
return true
}
return false
}
func (t *ExecTool) guardCommand(command, cwd string) string { func (t *ExecTool) guardCommand(command, cwd string) string {
cmd := strings.TrimSpace(command) cmd := strings.TrimSpace(command)
lower := strings.ToLower(cmd) lower := strings.ToLower(cmd)
@ -322,6 +365,7 @@ func (t *ExecTool) guardCommand(command, cwd string) string {
} }
if t.restrictToWorkspace { if t.restrictToWorkspace {
// Check for explicit path traversal sequences
if strings.Contains(cmd, "..\\") || strings.Contains(cmd, "../") { if strings.Contains(cmd, "..\\") || strings.Contains(cmd, "../") {
return "Command blocked by safety guard (path traversal detected)" return "Command blocked by safety guard (path traversal detected)"
} }
@ -334,6 +378,12 @@ func (t *ExecTool) guardCommand(command, cwd string) string {
matches := absolutePathPattern.FindAllString(cmd, -1) matches := absolutePathPattern.FindAllString(cmd, -1)
for _, raw := range matches { for _, raw := range matches {
// Skip URL paths (e.g., wttr.in/Beijing in curl commands)
// URL paths typically follow a dot or are part of a URL pattern
if isURLPath(cmd, raw) {
continue
}
p, err := filepath.Abs(raw) p, err := filepath.Abs(raw)
if err != nil { if err != nil {
continue continue