{"record":{"id":"94bfbbe81d68f4c9","repo":"AlistGo/alist","slug":"errarchiveillegalpath","errorCode":"ErrArchiveIllegalPath","errorMessage":"archive entry has illegal path: %s","messagePattern":"archive entry has illegal path: (.+?)","errorType":"exception","errorClass":"ErrArchiveIllegalPath","httpStatus":null,"severity":"error","filePath":"internal/archive/archives/archives.go","lineNumber":149,"sourceCode":"\t\t\trelPath := strings.TrimPrefix(p, path+\"/\")\n\t\t\tif relPath == \"\" || relPath == \".\" {\n\t\t\t\tif d.IsDir() {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t}\n\t\t\tdstPath, err := tool.SecureJoin(outputPath, relPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif d.IsDir() {\n\t\t\t\treturn os.MkdirAll(dstPath, 0700)\n\t\t\t}\n\t\t\tinfo, err := d.Info()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif !info.Mode().IsRegular() {\n\t\t\t\treturn fmt.Errorf(\"%w: %s\", tool.ErrArchiveIllegalPath, p)\n\t\t\t}\n\t\t\tif err := os.MkdirAll(filepath.Dir(dstPath), 0700); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn decompress(fsys, p, dstPath, func(_ float64) {}, limiter)\n\t\t})\n\t} else {\n\t\tentryName := stdpath.Base(path)\n\t\tdstPath, e := tool.SecureJoin(outputPath, entryName)\n\t\tif e != nil {\n\t\t\treturn e\n\t\t}\n\t\tif err = os.MkdirAll(filepath.Dir(dstPath), 0700); err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = decompress(fsys, path, dstPath, up, limiter)\n\t}\n\treturn filterPassword(err)","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/archive/archives/archives.go#L131-L167","documentation":"Security guard in the generic archives decompressor (Archives.Decompress walking an extracted fs.FS directory tree). After SecureJoin resolves the destination, each entry's FileInfo mode is checked; any non-regular, non-directory entry — symlink, device, FIFO — is rejected with the ErrArchiveIllegalPath sentinel. This blocks archive members that would otherwise write special files or escape via links during extraction.","triggerScenarios":"Decompressing an archive (zip/tar/etc. handled via the archives tool) whose inner directory contains a symlink, hardlink, char/block device, or FIFO entry, when the user extracts a folder (InnerPath resolves to a directory and fs.WalkDir runs).","commonSituations":"Linux-created tarballs preserving symlinks; macOS app bundles with symlinks; malicious or unusual archives containing device nodes; extracting system backup archives.","solutions":["Confirm the archive actually needs the special entries; re-create it with symlinks dereferenced (e.g. tar -h / zip --symlinks off)","Extract such archives with a system tool that supports preserving special files instead of the built-in decompressor","If you control the archive producer, package regular files only","Do not remove the check — it is a deliberate Zip-Slip/special-file defense"],"exampleFix":"# before: archive contains symlinks\ntar czf bundle.tgz mydir/   # mydir has symlinks\n\n# after: dereference symlinks when packing\ntar czfhs bundle.tgz mydir/","handlingStrategy":"validation","validationCode":"// Go: pre-walk the archive fs and reject/flag non-regular entries before extracting\nfunc hasSpecialEntries(fsys fs.FS) (bool, error) {\n    bad := false\n    err := fs.WalkDir(fsys, \".\", func(p string, d fs.DirEntry, err error) error {\n        if err != nil { return err }\n        if d.IsDir() { return nil }\n        info, err := d.Info(); if err != nil { return err }\n        if !info.Mode().IsRegular() { bad = true }\n        return nil\n    })\n    return bad, err\n}","typeGuard":"func isSafeArchiveEntry(info fs.FileInfo) bool {\n    return info.Mode().IsRegular() || info.IsDir()\n}","tryCatchPattern":"// Go: sentinel check with errors.Is, skip-and-continue instead of aborting\nif err := archivesTool.Decompress(ss, out, args, up); err != nil {\n    if errors.Is(err, tool.ErrArchiveIllegalPath) {\n        // refuse or quarantine the archive; do not retry with the same input\n    }\n}","preventionTips":["Only extract archives from trusted sources","Pre-scan listings for link/device members (tar tvf / unzip -l) in CI before extraction","Repack Unix archives with dereferenced symlinks when special files are not needed"],"tags":["archive","security","zip-slip","symlink","extraction"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}