From e7585e81851bd1980815d40adc2ec42a238a775a Mon Sep 17 00:00:00 2001 From: Dmitrii Balabanov Date: Sun, 8 Mar 2026 00:11:08 +0200 Subject: [PATCH] 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 --- pkg/config/config.go | 2 ++ pkg/session/manager.go | 12 +++++++++--- pkg/session/tasks.go | 8 +++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index e8bb60274..f8bd15e83 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -953,6 +953,8 @@ func (t *ToolsConfig) IsToolEnabled(name string) bool { return t.WriteFile.Enabled case "mcp": return t.MCP.Enabled + case "tasktool": + return t.TaskTool.Enabled default: return true } diff --git a/pkg/session/manager.go b/pkg/session/manager.go index f39a92d1e..1f953827f 100644 --- a/pkg/session/manager.go +++ b/pkg/session/manager.go @@ -151,13 +151,19 @@ func (sm *SessionManager) Save(key string) error { 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) // filepath.IsLocal rejects empty names, "..", absolute paths, and // OS-reserved device names (NUL, COM1 … on Windows). - // The extra checks reject "." and any directory separators so that - // the session file is always written directly inside sm.storage. - if filename == "." || !filepath.IsLocal(filename) || strings.ContainsAny(filename, `/\`) { + // The extra check rejects "." so that the session file is always + // written directly inside sm.storage. + if filename == "." || !filepath.IsLocal(filename) { return os.ErrInvalid } diff --git a/pkg/session/tasks.go b/pkg/session/tasks.go index 48f0c2aeb..b4adaeae4 100644 --- a/pkg/session/tasks.go +++ b/pkg/session/tasks.go @@ -154,9 +154,15 @@ func (tm *TaskManager) Save(key string) error { if err := os.MkdirAll(tm.storage, 0o755); err != nil { 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" - if filename == "." || !filepath.IsLocal(filename) || strings.ContainsAny(filename, "/\\") { + if filename == "." || !filepath.IsLocal(filename) { return os.ErrInvalid }