{"record":{"id":"8614b6386da392c4","repo":"Billionmail/BillionMail","slug":"illegal-file-path","errorCode":null,"errorMessage":"illegal file path: ","messagePattern":"illegal file path: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"core/internal/service/compress/gzip.go","lineNumber":151,"sourceCode":"\t\t// remove ../ from filename\n\t\tarcName := filepath.ToSlash(filepath.Clean(header.Name))\n\n\t\tif strings.Contains(arcName, \"../\") {\n\t\t\tarcName = strings.Replace(arcName, \"../\", \"\", -1)\n\t\t}\n\n\t\tfilename := filepath.Join(dst, arcName)\n\n\t\t// get absolute path of the file\n\t\tfilenameAbs, err := filepath.Abs(filename)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// check if the file is under the decompression target path\n\t\tif !strings.HasPrefix(filenameAbs, dstAbs) {\n\t\t\treturn errors.New(\"illegal file path: \" + filename)\n\t\t}\n\n\t\t// check if it's a directory\n\t\t// if it's a directory, create it and skip\n\t\tif header.FileInfo().IsDir() {\n\t\t\terr = os.MkdirAll(filename, 0755)\n\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// create directory\n\t\terr = os.MkdirAll(filepath.Dir(filename), 0755)\n\n\t\tif err != nil {","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/compress/gzip.go#L133-L169","documentation":"During gzip decompression, decompressHelper resolves each tar entry's filename to an absolute path and verifies it stays under the destination root. If the archive entry escapes the target path (e.g. via '../' path traversal), the unpacker refuses it to prevent a Zip-Slip attack. The offending entry name is appended to the message.","triggerScenarios":"Calling GzipUnpacker.Decompress on a .tar.gz whose entries contain absolute paths or '../' sequences that resolve outside dst; typically archives crafted by attackers or produced on other directory layouts.","commonSituations":"Processing untrusted user-uploaded archives; legacy archives with absolute paths; tooling that builds tar entries without filepath.Join on the base dir.","solutions":["Reject/quarantine the archive — it likely contains a path-traversal (Zip-Slip) entry","Rebuild the archive so entries are relative paths under a single root directory","Sanitize entries on the producing side (strip leading '/' and '..' components)","If trusted and intentional, extract with a lower-level tool that permits those paths — at your own risk"],"exampleFix":"// before (producer)\nhdr.Name = \"/etc/passwd\"\n// after\nhdr.Name = filepath.Join(\"root\", \"/etc/passwd\") // relative, stays under extraction dir","handlingStrategy":"validation","validationCode":"ok, err := func() (bool, error) {\n\tr, err := os.Open(archivePath); if err != nil { return false, err }\n\tdefer r.Close()\n\tgz, _ := gzip.NewReader(r)\n\ttr := tar.NewReader(gz)\n\tdstAbs, _ := filepath.Abs(dst)\n\tfor {\n\t\th, err := tr.Next(); if err == io.EOF { return true, nil }; if err != nil { return false, err }\n\t\tabs, _ := filepath.Abs(filepath.Join(dst, h.Name))\n\t\tif !strings.HasPrefix(abs, dstAbs+string(os.PathSeparator)) { return false, fmt.Errorf(\"unsafe entry: %s\", h.Name) }\n\t}\n}()\n_ = ok","typeGuard":null,"tryCatchPattern":"if err := u.Decompress(dst, src); err != nil && strings.HasPrefix(err.Error(), \"illegal file path\") {\n\t// quarantine archive, log offending entry from err message, do not retry\n}","preventionTips":["Treat all third-party archives as untrusted; never bypass the traversal check","Scan archive entries (names only) before extraction in a sandbox","Generate archives with relative, cleaned paths only","Keep the extraction root dedicated and least-privilege"],"tags":["go","compression","gzip","path-traversal","security"],"backgroundTag":"zip-slip-path-traversal","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}