Skip to content

Commit 9db5488

Browse files
committed
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.
1 parent ba01cb7 commit 9db5488

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

cmd/analyze/delete.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,17 @@ func trashPathWithProgress(root string, counter *int64) (int64, error) {
122122
// moveToTrash uses macOS Finder to move a file/directory to Trash.
123123
// This is the safest method as it uses the system's native trash mechanism.
124124
func moveToTrash(path string) error {
125+
// Validate raw input before Abs resolves ".." components away.
126+
if err := validatePath(path); err != nil {
127+
return err
128+
}
129+
125130
absPath, err := filepath.Abs(path)
126131
if err != nil {
127132
return fmt.Errorf("failed to resolve path: %w", err)
128133
}
129134

130-
// Validate path to prevent path traversal attacks.
135+
// Validate resolved path as well (defense-in-depth).
131136
if err := validatePath(absPath); err != nil {
132137
return err
133138
}

cmd/analyze/delete_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package main
55
import (
66
"os"
77
"path/filepath"
8+
"strings"
89
"testing"
910
)
1011

@@ -82,6 +83,17 @@ func TestMoveToTrashNonExistent(t *testing.T) {
8283
}
8384
}
8485

86+
func TestMoveToTrashRejectsTraversal(t *testing.T) {
87+
// Verify the full production path rejects ".." before filepath.Abs resolves it.
88+
err := moveToTrash("/tmp/fakedir/../../../etc/passwd")
89+
if err == nil {
90+
t.Fatal("expected error for path with traversal components")
91+
}
92+
if !strings.Contains(err.Error(), "traversal") {
93+
t.Fatalf("expected traversal error, got: %v", err)
94+
}
95+
}
96+
8597
func TestValidatePath(t *testing.T) {
8698
tests := []struct {
8799
name string

0 commit comments

Comments
 (0)