Skip to content

Commit f44f9ac

Browse files
committed
Zip Splip mitigation
1 parent 18c6728 commit f44f9ac

1 file changed

Lines changed: 27 additions & 1 deletion

File tree

‎download.go‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"path/filepath"
99
"strconv"
10+
"strings"
1011
"sync"
1112

1213
"github.com/fxamacker/cbor/v2"
@@ -50,6 +51,24 @@ func download(key, domain, id, destination string) error {
5051
return downloadTraversal(downloader, key, domain, &node, destination)
5152
}
5253

54+
// safePath ensures the resulting path stays within the base directory
55+
func safePath(base, name string) (string, error) {
56+
joined := filepath.Join(base, name)
57+
absBase, err := filepath.Abs(base)
58+
if err != nil {
59+
return "", fmt.Errorf("getting absolute base path: %w", err)
60+
}
61+
absJoined, err := filepath.Abs(joined)
62+
if err != nil {
63+
return "", fmt.Errorf("getting absolute joined path: %w", err)
64+
}
65+
// Ensure the joined path is within the base directory
66+
if !strings.HasPrefix(absJoined, absBase+string(filepath.Separator)) && absJoined != absBase {
67+
return "", fmt.Errorf("path traversal detected: %s escapes %s", name, base)
68+
}
69+
return joined, nil
70+
}
71+
5372
func downloadTraversal(downloader *protocol.ParallelDownloader, key, domain string, node *protocol.Node, destination string) error {
5473
if node.Hash != nil {
5574
hash := *node.Hash
@@ -82,10 +101,17 @@ func downloadTraversal(downloader *protocol.ParallelDownloader, key, domain stri
82101
var mu sync.Mutex
83102
var wg sync.WaitGroup
84103
for name, child := range node.Children {
104+
childPath, err := safePath(destination, name)
105+
if err != nil {
106+
mu.Lock()
107+
errors = append(errors, err)
108+
mu.Unlock()
109+
continue
110+
}
85111
wg.Add(1)
86112
go func() {
87113
defer wg.Done()
88-
if err := downloadTraversal(downloader, key, domain, child, filepath.Join(destination, name)); err != nil {
114+
if err := downloadTraversal(downloader, key, domain, child, childPath); err != nil {
89115
mu.Lock()
90116
errors = append(errors, err)
91117
mu.Unlock()

0 commit comments

Comments
 (0)