{"record":{"id":"16c202c6af32e52d","repo":"k3s-io/k3s","slug":"tar-contained-invalid-name-error-q","errorCode":null,"errorMessage":"tar contained invalid name error %q","messagePattern":"tar contained invalid name error %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/untar/untar.go","lineNumber":59,"sourceCode":"\t}()\n\tzr, err := zstd.NewReader(r, zstd.WithDecoderMaxMemory(tarfile.MaxDecoderMemory))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error extracting zstd-compressed body: %v\", err)\n\t}\n\tdefer zr.Close()\n\ttr := tar.NewReader(zr)\n\tloggedChtimesError := false\n\tfor {\n\t\tf, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\tlogrus.Printf(\"tar reading error: %v\", err)\n\t\t\treturn fmt.Errorf(\"tar error: %v\", err)\n\t\t}\n\t\tif !validRelPath(f.Name) {\n\t\t\treturn fmt.Errorf(\"tar contained invalid name error %q\", f.Name)\n\t\t}\n\t\trel := filepath.FromSlash(f.Name)\n\t\tabs := filepath.Join(dir, rel)\n\n\t\tfi := f.FileInfo()\n\t\tmode := fi.Mode()\n\t\tswitch {\n\t\tcase mode.IsRegular():\n\t\t\t// Make the directory. This is redundant because it should\n\t\t\t// already be made by a directory entry in the tar\n\t\t\t// beforehand. Thus, don't check for errors; the next\n\t\t\t// write will fail with the same error.\n\t\t\tdir := filepath.Dir(abs)\n\t\t\tif !madeDir[dir] {\n\t\t\t\tif err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tmadeDir[dir] = true","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/k3s-io/k3s/blob/6ba341e396edc16b8dcae978a7c5e3ac7ee5606e/pkg/untar/untar.go#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the offending entries: zstd -d < bundle.tar.zst | tar -tvf - and look for absolute paths or '..' components","Re-create the archive with relative names, e.g. tar -C srcdir -cf bundle.tar . without -P/--absolute-names","If you control the producer, strip leading '/' and reject '..' components when writing entry names","If the archive is from an untrusted source, treat it as malicious and refuse to extract it"],"exampleFix":"# before (entries keep absolute names)\ntar -P -cf bundle.tar /data/app\n# after (relative names only)\ntar -C /data/app -cf bundle.tar .","handlingStrategy":"validation","validationCode":"import (\n\t\"archive/tar\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/klauspost/compress/zstd\"\n)\n\n// Pre-scan a zstd tarball for unsafe entry names before extracting.\nfunc CheckTarballNames(r io.Reader) error {\n\tzr, err := zstd.NewReader(r)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer zr.Close()\n\ttr := tar.NewReader(zr)\n\tfor {\n\t\th, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\treturn nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif h.Name == \"\" || strings.Contains(h.Name, `\\`) || strings.HasPrefix(h.Name, \"/\") || strings.Contains(h.Name, \"../\") {\n\t\t\treturn fmt.Errorf(\"unsafe entry %q\", h.Name)\n\t\t}\n\t}\n}","typeGuard":"func isSafeTarName(p string) bool {\n\treturn p != \"\" && !strings.Contains(p, `\\`) && !strings.HasPrefix(p, \"/\") && !strings.Contains(p, \"../\")\n}","tryCatchPattern":"if err := untar.Untar(r, dir); err != nil {\n\tif strings.Contains(err.Error(), \"tar contained invalid name\") {\n\t\t// archive is malformed or hostile: quarantine it, do not retry\n\t\tlog.Fatalf(\"rejecting unsafe archive: %v\", err)\n\t}\n\treturn err\n}","preventionTips":["Only accept archives from trusted producers and verify checksums before extracting","When creating tars, always use tar -C dir so entry names stay relative","Never pass tar -P/--absolute-names when producing archives for automated extraction","Run a name pre-scan on any archive received from untrusted sources"],"tags":["go","tar","security","path-traversal","archive"],"backgroundTag":null,"analyzedSha":"6ba341e396edc16b8dcae978a7c5e3ac7ee5606e","analyzedAt":"2026-08-15T16:27:54.286Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}