k3s-io/k3s · error

tar contained invalid name error %q

Error message

tar contained invalid name error %q

What it means

Thrown by untar.Untar (which extracts a zstd-compressed tarball into a destination directory) when a tar entry's Name fails validRelPath: it is empty, contains a backslash, starts with '/', or contains '../'. This is a path-traversal (Zip Slip) guard: the entry name is joined onto the destination directory, so absolute or parent-relative names could write outside dir, and the archive is rejected before the entry is extracted.

Source

Thrown at pkg/untar/untar.go:59

	}()
	zr, err := zstd.NewReader(r, zstd.WithDecoderMaxMemory(tarfile.MaxDecoderMemory))
	if err != nil {
		return fmt.Errorf("error extracting zstd-compressed body: %v", err)
	}
	defer zr.Close()
	tr := tar.NewReader(zr)
	loggedChtimesError := false
	for {
		f, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			logrus.Printf("tar reading error: %v", err)
			return fmt.Errorf("tar error: %v", err)
		}
		if !validRelPath(f.Name) {
			return fmt.Errorf("tar contained invalid name error %q", f.Name)
		}
		rel := filepath.FromSlash(f.Name)
		abs := filepath.Join(dir, rel)

		fi := f.FileInfo()
		mode := fi.Mode()
		switch {
		case mode.IsRegular():
			// Make the directory. This is redundant because it should
			// already be made by a directory entry in the tar
			// beforehand. Thus, don't check for errors; the next
			// write will fail with the same error.
			dir := filepath.Dir(abs)
			if !madeDir[dir] {
				if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil {
					return err
				}
				madeDir[dir] = true

View on GitHub (pinned to 6ba341e396)

Solutions

  1. Inspect the offending entries: zstd -d < bundle.tar.zst | tar -tvf - and look for absolute paths or '..' components
  2. Re-create the archive with relative names, e.g. tar -C srcdir -cf bundle.tar . without -P/--absolute-names
  3. If you control the producer, strip leading '/' and reject '..' components when writing entry names
  4. If the archive is from an untrusted source, treat it as malicious and refuse to extract it

Example fix

# before (entries keep absolute names)
tar -P -cf bundle.tar /data/app
# after (relative names only)
tar -C /data/app -cf bundle.tar .
Defensive patterns

Strategy: validation

Validate before calling

import (
	"archive/tar"
	"fmt"
	"strings"

	"github.com/klauspost/compress/zstd"
)

// Pre-scan a zstd tarball for unsafe entry names before extracting.
func CheckTarballNames(r io.Reader) error {
	zr, err := zstd.NewReader(r)
	if err != nil {
		return err
	}
	defer zr.Close()
	tr := tar.NewReader(zr)
	for {
		h, err := tr.Next()
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		if h.Name == "" || strings.Contains(h.Name, `\`) || strings.HasPrefix(h.Name, "/") || strings.Contains(h.Name, "../") {
			return fmt.Errorf("unsafe entry %q", h.Name)
		}
	}
}

Type guard

func isSafeTarName(p string) bool {
	return p != "" && !strings.Contains(p, `\`) && !strings.HasPrefix(p, "/") && !strings.Contains(p, "../")
}

Try / catch

if err := untar.Untar(r, dir); err != nil {
	if strings.Contains(err.Error(), "tar contained invalid name") {
		// archive is malformed or hostile: quarantine it, do not retry
		log.Fatalf("rejecting unsafe archive: %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling untar.Untar(r, dir) on a tarball containing an entry whose Name is absolute (e.g. '/etc/passwd'), contains '..' segments ('../../x'), uses Windows separators (backslash paths), or has an empty name.

Common situations: Archives created with tar -P/--absolute-names; tars produced on Windows with backslash separators; hostile or tampered tarballs downloaded over the network; airgap image bundles that were repacked incorrectly.

Related errors


AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15). Data as JSON: /api/errors/16c202c6af32e52d. Report an issue: GitHub.