{"record":{"id":"8fa483fa61772be7","repo":"AlistGo/alist","slug":"errarchiveillegalpath-8fa483","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/utils.go","lineNumber":74,"sourceCode":"func filterPassword(err error) error {\n\tif err != nil && strings.Contains(err.Error(), \"password\") {\n\t\treturn errs.WrongArchivePassword\n\t}\n\treturn err\n}\n\nfunc decompress(fsys fs2.FS, filePath, dstPath string, up model.UpdateProgress, limiter *tool.SizeLimiter) error {\n\trc, err := fsys.Open(filePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rc.Close()\n\tstat, err := rc.Stat()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !stat.Mode().IsRegular() {\n\t\treturn fmt.Errorf(\"%w: %s\", tool.ErrArchiveIllegalPath, filePath)\n\t}\n\tf, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\t_, err = utils.CopyWithBuffer(limiter.WrapWriter(f), &stream.ReaderUpdatingProgress{\n\t\tReader: &stream.SimpleReaderWithSize{\n\t\t\tReader: rc,\n\t\t\tSize:   stat.Size(),\n\t\t},\n\t\tUpdateProgress: up,\n\t})\n\treturn err\n}\n","sourceCodeStart":56,"sourceCodeEnd":90,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/archive/archives/utils.go#L56-L90","documentation":"Second guard in the archives decompression path: decompress() in internal/archive/archives/utils.go opens the entry from the virtual fs.FS and stats it before writing; a mode that is not a regular file (symlink, device, FIFO) triggers ErrArchiveIllegalPath. It complements the WalkDir check by re-validating at the actual copy step.","triggerScenarios":"Extracting any archive through the Archives tool where the entry being copied (single-file extraction, or a file reached inside a walked directory) reports a non-regular Stat mode — typically a stored symlink or special file entry.","commonSituations":"Same class as the walker guard: tars with symlinks, crafted archives, filesystem-backed pseudo-archives; races where the entry changes between walk and open are also caught here.","solutions":["Repack the archive with special entries dereferenced or omitted","Use an external extractor when preserving symlinks/devices is a requirement","Verify integrity of the archive (re-download) if the entry type looks corrupted"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":"func isRegularMode(m fs.FileMode) bool { return m.IsRegular() }","tryCatchPattern":"if err := decompress(fsys, p, dstPath, up, limiter); err != nil {\n    if errors.Is(err, tool.ErrArchiveIllegalPath) {\n        return fmt.Errorf(\"unsafe member %q: %w\", p, err)\n    }\n    return err\n}","preventionTips":["Keep the copy-step guard; it catches entries that change type between walk and open","Scan archives for special entries before extraction","Repack untrusted archives through a sanitizer that dereferences links"],"tags":["archive","security","symlink","extraction"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}