Skip to content
This repository was archived by the owner on Nov 19, 2024. It is now read-only.

Commit e8249d1

Browse files
committed
fix: prevent extraction of archived files outside target path
1 parent 26cf5bb commit e8249d1

4 files changed

Lines changed: 36 additions & 10 deletions

File tree

cmd/archiver/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ func main() {
2727
}
2828
err = ff.Make(filename, os.Args[3:])
2929
case "open":
30-
dest := ""
30+
dest, err := os.Getwd()
31+
if err != nil {
32+
fatal(err)
33+
}
3134
if len(os.Args) == 4 {
3235
dest = os.Args[3]
3336
} else if len(os.Args) > 4 {

rar.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,16 @@ func (rarFormat) Read(input io.Reader, destination string) error {
7272
return err
7373
}
7474

75+
// to avoid zip slip (writing outside of the destination), we
76+
// resolve the target path, and make sure it's nested in
77+
// the intended destination, or bail otherwise.
78+
destpath := filepath.Join(destination, header.Name)
79+
if !strings.HasPrefix(destpath, destination) {
80+
return fmt.Errorf("%s: illegal file path", header.Name)
81+
}
82+
7583
if header.IsDir {
76-
err = mkdir(filepath.Join(destination, header.Name))
84+
err = mkdir(destpath)
7785
if err != nil {
7886
return err
7987
}
@@ -82,12 +90,12 @@ func (rarFormat) Read(input io.Reader, destination string) error {
8290

8391
// if files come before their containing folders, then we must
8492
// create their folders before writing the file
85-
err = mkdir(filepath.Dir(filepath.Join(destination, header.Name)))
93+
err = mkdir(filepath.Dir(destpath))
8694
if err != nil {
8795
return err
8896
}
8997

90-
err = writeNewFile(filepath.Join(destination, header.Name), rr, header.Mode())
98+
err = writeNewFile(destpath, rr, header.Mode())
9199
if err != nil {
92100
return err
93101
}

tar.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,23 @@ func untar(tr *tar.Reader, destination string) error {
219219

220220
// untarFile untars a single file from tr with header header into destination.
221221
func untarFile(tr *tar.Reader, header *tar.Header, destination string) error {
222+
// to avoid zip slip (writing outside of the destination), we resolve
223+
// the target path, and make sure it's nested in the intended
224+
// destination, or bail otherwise.
225+
destpath := filepath.Join(destination, header.Name)
226+
if !strings.HasPrefix(destpath, destination) {
227+
return fmt.Errorf("%s: illegal file path", header.Name)
228+
}
229+
222230
switch header.Typeflag {
223231
case tar.TypeDir:
224-
return mkdir(filepath.Join(destination, header.Name))
232+
return mkdir(destpath)
225233
case tar.TypeReg, tar.TypeRegA, tar.TypeChar, tar.TypeBlock, tar.TypeFifo:
226-
return writeNewFile(filepath.Join(destination, header.Name), tr, header.FileInfo().Mode())
234+
return writeNewFile(destpath, tr, header.FileInfo().Mode())
227235
case tar.TypeSymlink:
228-
return writeNewSymbolicLink(filepath.Join(destination, header.Name), header.Linkname)
236+
return writeNewSymbolicLink(destpath, header.Linkname)
229237
case tar.TypeLink:
230-
return writeNewHardLink(filepath.Join(destination, header.Name), filepath.Join(destination, header.Linkname))
238+
return writeNewHardLink(destpath, filepath.Join(destination, header.Linkname))
231239
default:
232240
return fmt.Errorf("%s: unknown type flag: %c", header.Name, header.Typeflag)
233241
}

zip.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,15 @@ func unzipAll(r *zip.Reader, destination string) error {
187187
}
188188

189189
func unzipFile(zf *zip.File, destination string) error {
190+
// to avoid zip slip (writing outside of the destination), we resolve
191+
// the target path, and make sure it's nested in the intended
192+
// destination, or bail otherwise.
193+
destpath := filepath.Join(destination, zf.Name)
194+
if !strings.HasPrefix(destpath, destination) {
195+
return fmt.Errorf("%s: illegal file path", zf.Name)
196+
}
190197
if strings.HasSuffix(zf.Name, "/") {
191-
return mkdir(filepath.Join(destination, zf.Name))
198+
return mkdir(destpath)
192199
}
193200

194201
rc, err := zf.Open()
@@ -197,7 +204,7 @@ func unzipFile(zf *zip.File, destination string) error {
197204
}
198205
defer rc.Close()
199206

200-
return writeNewFile(filepath.Join(destination, zf.Name), rc, zf.FileInfo().Mode())
207+
return writeNewFile(destpath, rc, zf.FileInfo().Mode())
201208
}
202209

203210
// compressedFormats is a (non-exhaustive) set of lowercased

0 commit comments

Comments
 (0)