fix: restore path-traversal rejection and enable tasktool config flag

- Check original key for '/' and '\' before sanitizing in session/manager.go
  and session/tasks.go, so traversal-like keys are rejected rather than
  silently normalized by SanitizeFilename (fixes TestSave_RejectsPathTraversal)
- Add "tasktool" case to IsToolEnabled switch so tools.tasktool.enabled: false
  actually disables the tool instead of falling through to default: true
This commit is contained in:
Dmitrii Balabanov 2026-03-08 00:11:08 +02:00
parent 896fb08f93
commit e7585e8185
3 changed files with 18 additions and 4 deletions

View file

@ -953,6 +953,8 @@ func (t *ToolsConfig) IsToolEnabled(name string) bool {
return t.WriteFile.Enabled return t.WriteFile.Enabled
case "mcp": case "mcp":
return t.MCP.Enabled return t.MCP.Enabled
case "tasktool":
return t.TaskTool.Enabled
default: default:
return true return true
} }

View file

@ -151,13 +151,19 @@ func (sm *SessionManager) Save(key string) error {
return nil return nil
} }
// Reject keys containing path separators before sanitizing, so that
// traversal-like inputs (e.g. "foo/bar") are never silently normalized.
if strings.ContainsAny(key, `/\`) {
return os.ErrInvalid
}
filename := fileutil.SanitizeFilename(key) filename := fileutil.SanitizeFilename(key)
// filepath.IsLocal rejects empty names, "..", absolute paths, and // filepath.IsLocal rejects empty names, "..", absolute paths, and
// OS-reserved device names (NUL, COM1 … on Windows). // OS-reserved device names (NUL, COM1 … on Windows).
// The extra checks reject "." and any directory separators so that // The extra check rejects "." so that the session file is always
// the session file is always written directly inside sm.storage. // written directly inside sm.storage.
if filename == "." || !filepath.IsLocal(filename) || strings.ContainsAny(filename, `/\`) { if filename == "." || !filepath.IsLocal(filename) {
return os.ErrInvalid return os.ErrInvalid
} }

View file

@ -154,9 +154,15 @@ func (tm *TaskManager) Save(key string) error {
if err := os.MkdirAll(tm.storage, 0o755); err != nil { if err := os.MkdirAll(tm.storage, 0o755); err != nil {
return err return err
} }
// Reject keys containing path separators before sanitizing, so that
// traversal-like inputs (e.g. "foo/bar") are never silently normalized.
if strings.ContainsAny(key, "/\\") {
return os.ErrInvalid
}
filename := fileutil.SanitizeFilename(key) + "_tasks.json" filename := fileutil.SanitizeFilename(key) + "_tasks.json"
if filename == "." || !filepath.IsLocal(filename) || strings.ContainsAny(filename, "/\\") { if filename == "." || !filepath.IsLocal(filename) {
return os.ErrInvalid return os.ErrInvalid
} }