fix: harden cmd mode cd redirection and allow ./executable in guard
- handleCdCommand: redirect cd, cd ~, cd /, cd /path to workspace directory instead of $HOME or system root for safety - guardCommand: fix path regex false positive that extracted "/exe" from "./exe.sh" and blocked it as absolute path outside workspace Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8bba78a413
commit
5e11b083ed
2 changed files with 21 additions and 9 deletions
|
|
@ -1400,25 +1400,30 @@ func (al *AgentLoop) executeCmdMode(ctx context.Context, agent *AgentInstance, c
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleCdCommand handles the cd command in command mode, updating per-session working directory.
|
// handleCdCommand handles the cd command in command mode, updating per-session working directory.
|
||||||
|
// Special paths (cd, cd ~, cd /, cd /xxx) are redirected to the workspace directory for safety.
|
||||||
func (al *AgentLoop) handleCdCommand(content, sessionKey string, agent *AgentInstance) string {
|
func (al *AgentLoop) handleCdCommand(content, sessionKey string, agent *AgentInstance) string {
|
||||||
parts := strings.Fields(content)
|
parts := strings.Fields(content)
|
||||||
|
workspace := agent.Workspace
|
||||||
var target string
|
var target string
|
||||||
|
|
||||||
if len(parts) < 2 || parts[1] == "~" {
|
if len(parts) < 2 || parts[1] == "~" || parts[1] == "/" {
|
||||||
home, _ := os.UserHomeDir()
|
// cd, cd ~, cd / → always go to workspace
|
||||||
target = home
|
target = workspace
|
||||||
} else {
|
} else {
|
||||||
target = parts[1]
|
target = parts[1]
|
||||||
// Expand ~ prefix
|
// Expand ~ prefix: treat ~ as workspace root (not $HOME)
|
||||||
if strings.HasPrefix(target, "~/") {
|
if strings.HasPrefix(target, "~/") {
|
||||||
home, _ := os.UserHomeDir()
|
target = workspace + target[1:]
|
||||||
target = home + target[1:]
|
}
|
||||||
|
// Absolute paths (e.g. cd /etc) → redirect to workspace
|
||||||
|
if filepath.IsAbs(target) {
|
||||||
|
target = workspace
|
||||||
}
|
}
|
||||||
// Resolve relative paths
|
// Resolve relative paths
|
||||||
if !filepath.IsAbs(target) {
|
if !filepath.IsAbs(target) {
|
||||||
currentDir := al.getSessionWorkDir(sessionKey)
|
currentDir := al.getSessionWorkDir(sessionKey)
|
||||||
if currentDir == "" {
|
if currentDir == "" {
|
||||||
currentDir = agent.Workspace
|
currentDir = workspace
|
||||||
}
|
}
|
||||||
target = filepath.Join(currentDir, target)
|
target = filepath.Join(currentDir, target)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -290,9 +290,16 @@ func (t *ExecTool) guardCommand(command, cwd string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
pathPattern := regexp.MustCompile(`[A-Za-z]:\\[^\\\"']+|/[^\s\"']+`)
|
pathPattern := regexp.MustCompile(`[A-Za-z]:\\[^\\\"']+|/[^\s\"']+`)
|
||||||
matches := pathPattern.FindAllString(cmd, -1)
|
matchIndices := pathPattern.FindAllStringIndex(cmd, -1)
|
||||||
|
|
||||||
|
for _, loc := range matchIndices {
|
||||||
|
raw := cmd[loc[0]:loc[1]]
|
||||||
|
// Skip relative paths like ./executable — the regex extracts
|
||||||
|
// "/executable" from "./executable" but it's not an absolute path.
|
||||||
|
if loc[0] > 0 && cmd[loc[0]-1] == '.' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, raw := range matches {
|
|
||||||
p, err := filepath.Abs(raw)
|
p, err := filepath.Abs(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue