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 327c902
Show file tree
Hide file tree
Showing 2 changed files with 52 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
44 changes: 44 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,43 @@ 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()),
}

if err := tb.WriteHeader(&header); err != nil {
t.Fatal(err)
}

_, err := io.Copy(tb, data)
if err != nil {
t.Fatal(err)
}

tb.Close()
}

0 comments on commit 327c902

Please sign in to comment.