Skip to content

Commit 07971c0

Browse files
committed
security: clean file path on extracting
Reported by George Gkitsas.
1 parent cf4aeaa commit 07971c0

5 files changed

Lines changed: 15 additions & 5 deletions

File tree

cae.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package cae
1818
import (
1919
"io"
2020
"os"
21+
"path"
2122
"strings"
2223
)
2324

@@ -106,3 +107,8 @@ func Copy(dest, src string) error {
106107
}
107108
return os.Chmod(dest, si.Mode())
108109
}
110+
111+
// Clean cleans up given path and returns a relative path that goes straight down.
112+
func Clean(p string) string {
113+
return strings.Trim(path.Clean("/"+p), "/")
114+
}

tz/read.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"io"
2121
"os"
2222
"strings"
23+
24+
"github.com/unknwon/cae"
2325
)
2426

2527
// A ReadCloser represents a caller closable file reader.
@@ -88,7 +90,7 @@ func (tz *TzArchive) syncFiles() {
8890
for i, f := range tz.File {
8991
tz.files[i] = &File{}
9092
tz.files[i].Header = f
91-
tz.files[i].Name = strings.Replace(f.Name, "\\", "/", -1)
93+
tz.files[i].Name = cae.Clean(strings.ReplaceAll(f.Name, "\\", "/"))
9294
if f.FileInfo().IsDir() && !strings.HasSuffix(tz.files[i].Name, "/") {
9395
tz.files[i].Name += "/"
9496
}

tz/write.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ var defaultExtractFunc = func(fullName string, fi os.FileInfo) error {
6969
// specified destination.
7070
// It accepts a function as a middleware for custom operations.
7171
func (tz *TzArchive) ExtractToFunc(destPath string, fn cae.HookFunc, entries ...string) (err error) {
72-
destPath = strings.Replace(destPath, "\\", "/", -1)
72+
destPath = strings.ReplaceAll(destPath, "\\", "/")
7373
isHasEntry := len(entries) > 0
7474
if Verbose {
7575
fmt.Println("Extracting " + tz.FileName + "...")
@@ -103,7 +103,7 @@ func (tz *TzArchive) ExtractToFunc(destPath string, fn cae.HookFunc, entries ...
103103
return err
104104
}
105105

106-
h.Name = strings.Replace(h.Name, "\\", "/", -1)
106+
h.Name = cae.Clean(strings.ReplaceAll(h.Name, "\\", "/"))
107107

108108
// Directory.
109109
if h.Typeflag == tar.TypeDir {

zip/read.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"archive/zip"
1919
"os"
2020
"strings"
21+
22+
"github.com/unknwon/cae"
2123
)
2224

2325
// OpenFile is the generalized open call; most users will use Open
@@ -58,7 +60,7 @@ func (z *ZipArchive) Open(name string, flag int, perm os.FileMode) error {
5860
if err != nil {
5961
return err
6062
}
61-
z.files[i].Name = strings.Replace(f.Name, "\\", "/", -1)
63+
z.files[i].Name = cae.Clean(strings.ReplaceAll(f.Name, "\\", "/"))
6264
if f.FileInfo().IsDir() && !strings.HasSuffix(z.files[i].Name, "/") {
6365
z.files[i].Name += "/"
6466
}

zip/write.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func (z *ZipArchive) ExtractToFunc(destPath string, fn cae.HookFunc, entries ...
8181
}
8282
os.MkdirAll(destPath, os.ModePerm)
8383
for _, f := range z.File {
84-
f.Name = strings.Replace(f.Name, "\\", "/", -1)
84+
f.Name = cae.Clean(strings.ReplaceAll(f.Name, "\\", "/"))
8585

8686
// Directory.
8787
if strings.HasSuffix(f.Name, "/") {

0 commit comments

Comments
 (0)