Skip to content

Commit

Permalink
Patch malicious tarballs
Browse files Browse the repository at this point in the history
Tarballs with files containing directory traversal components can write
files to unintended locations. This change ensures the Untar function
will error when a given tarball has a traversal component (..).

See https://cwe.mitre.org/data/definitions/22.html
  • Loading branch information
chrisdoherty4 committed Nov 17, 2023
1 parent 96f3aae commit 2a4b6de
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
8 changes: 8 additions & 0 deletions pkg/tar/untar.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package tar

import (
"archive/tar"
"fmt"
"io"
"os"
"strings"
)

func UntarFile(tarFile, dstFolder string) error {
Expand Down Expand Up @@ -32,6 +34,12 @@ func Untar(source io.Reader, router Router) error {
continue
}

// Prevent malicous directory traversals.
// https://cwe.mitre.org/data/definitions/22.html
if strings.Contains(header.Name, "..") {
return fmt.Errorf("file in tarball contains a directory traversal component (..): %v", header.Name)
}

info := header.FileInfo()
if info.IsDir() {
if err = os.MkdirAll(path, info.Mode()); err != nil {
Expand Down
41 changes: 41 additions & 0 deletions pkg/tar/untar_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package tar_test

import (
stdtar "archive/tar"
"bytes"
"io"
"io/fs"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -30,3 +34,40 @@ func TestUntarFile(t *testing.T) {
g.Expect(filepath.Join(untarFolder, "dummy3")).To(BeADirectory())
g.Expect(filepath.Join(untarFolder, "dummy3", "dummy4")).To(BeARegularFile())
}

func TestUntarFile_DirTraversalComponents(t *testing.T) {
// This test ensures Untar fails when a tarball contains paths with directory traversal
// components. It addresses https://cwe.mitre.org/data/definitions/22.html.
g := NewWithT(t)

dir := t.TempDir()
tarPath := filepath.Join(dir, "test")
fh, err := os.Create(tarPath)
g.Expect(err).To(Succeed())

createArbitraryTarball(t, fh)

g.Expect(tar.UntarFile(tarPath, dir)).ToNot(Succeed())
}

func createArbitraryTarball(t *testing.T, w io.Writer) {
t.Helper()

tb := stdtar.NewWriter(w)

data := bytes.NewBufferString("Hello, world!")
header := stdtar.Header{
Name: "../foobar",
Mode: int64(fs.ModePerm),
Typeflag: stdtar.TypeReg,
Size: int64(data.Len()),
}

tb.WriteHeader(&header)

Check failure on line 66 in pkg/tar/untar_test.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `tb.WriteHeader` is not checked (errcheck)
_, err := io.Copy(tb, data)
if err != nil {
t.Fatal(err)
}

tb.Close()
}

0 comments on commit 2a4b6de

Please sign in to comment.