From 9db5488397a01c588ecb792c4a8bb0c42530004e Mon Sep 17 00:00:00 2001 From: Tw93 Date: Sat, 14 Mar 2026 10:39:33 +0800 Subject: [PATCH] security: validate raw path in moveToTrash before filepath.Abs resolves traversal filepath.Abs resolves ".." components, so the existing validatePath call on the resolved path could never catch traversal attempts. Move validation before Abs to reject raw input with "..", keeping the post-Abs check as defense-in-depth. --- cmd/analyze/delete.go | 7 ++++++- cmd/analyze/delete_test.go | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/cmd/analyze/delete.go b/cmd/analyze/delete.go index 2855a28..00d07b4 100644 --- a/cmd/analyze/delete.go +++ b/cmd/analyze/delete.go @@ -122,12 +122,17 @@ func trashPathWithProgress(root string, counter *int64) (int64, error) { // moveToTrash uses macOS Finder to move a file/directory to Trash. // This is the safest method as it uses the system's native trash mechanism. func moveToTrash(path string) error { + // Validate raw input before Abs resolves ".." components away. + if err := validatePath(path); err != nil { + return err + } + absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("failed to resolve path: %w", err) } - // Validate path to prevent path traversal attacks. + // Validate resolved path as well (defense-in-depth). if err := validatePath(absPath); err != nil { return err } diff --git a/cmd/analyze/delete_test.go b/cmd/analyze/delete_test.go index 4132e2e..f6b011f 100644 --- a/cmd/analyze/delete_test.go +++ b/cmd/analyze/delete_test.go @@ -5,6 +5,7 @@ package main import ( "os" "path/filepath" + "strings" "testing" ) @@ -82,6 +83,17 @@ func TestMoveToTrashNonExistent(t *testing.T) { } } +func TestMoveToTrashRejectsTraversal(t *testing.T) { + // Verify the full production path rejects ".." before filepath.Abs resolves it. + err := moveToTrash("/tmp/fakedir/../../../etc/passwd") + if err == nil { + t.Fatal("expected error for path with traversal components") + } + if !strings.Contains(err.Error(), "traversal") { + t.Fatalf("expected traversal error, got: %v", err) + } +} + func TestValidatePath(t *testing.T) { tests := []struct { name string