{"record":{"id":"5bebc104a2e26777","repo":"AlistGo/alist","slug":"total-size-of-decompressed-files-exceeds-the-limit","errorCode":null,"errorMessage":"total size of decompressed files exceeds the limit","messagePattern":"total size of decompressed files exceeds the limit","errorType":"exception","errorClass":"ErrExtractSizeExceeded","httpStatus":null,"severity":"error","filePath":"internal/archive/tool/limiter.go","lineNumber":9,"sourceCode":"package tool\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"sync/atomic\"\n)\n\nvar ErrExtractSizeExceeded = errors.New(\"total size of decompressed files exceeds the limit\")\n\n// SizeLimiter limits the total bytes written by one decompress task.\n// A non-positive max means no limit.\ntype SizeLimiter struct {\n\tremain  int64\n\tlimited bool\n}\n\nfunc NewSizeLimiter(max int64) *SizeLimiter {\n\tif max <= 0 {\n\t\treturn &SizeLimiter{}\n\t}\n\treturn &SizeLimiter{remain: max, limited: true}\n}\n\nfunc (l *SizeLimiter) WrapWriter(w io.Writer) io.Writer {\n\tif l == nil || !l.limited {\n\t\treturn w","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/archive/tool/limiter.go#L1-L27","documentation":"ErrExtractSizeExceeded is returned by internal/archive/tool's SizeLimiter when the cumulative bytes written by one decompression task would exceed the configured max (a non-positive max disables the limit). It is a decompression-bomb mitigation: extraction stops as soon as the remaining budget would go negative.","triggerScenarios":"Extracting an archive whose expanded content exceeds the configured size cap — including malicious zip/gzip bombs where a tiny archive expands to hundreds of GB, or merely a legitimately large archive against a low cap. Any writer wrapped by SizeLimiter during archive extraction can trigger it once remain drops below the incoming write size.","commonSituations":"Default extraction limits set lower than the archives users actually upload; a hostile upload containing a compression bomb; nested archives that expand recursively; caps configured in bytes vs MB confusion (e.g. 100 interpreted as 100 bytes).","solutions":["Raise the decompression size limit in settings if the archive is trusted and legitimately large","Scan/inspect the archive (list entries and sizes) before extracting — a 10KB file claiming 500GB is a bomb","Verify the limit's unit (bytes vs MiB) in your configuration","Reject or quarantine the archive if it is untrusted and keeps tripping the limit"],"exampleFix":"// before\nlimiter := tool.NewSizeLimiter(1024) // accidental 1KB cap\n\n// after\nlimiter := tool.NewSizeLimiter(10 << 30) // 10GiB cap","handlingStrategy":"validation","validationCode":"var total int64\nfor _, h := range archive.Headers() { total += h.Size }\nif limiterMax > 0 && total > limiterMax { return tool.ErrExtractSizeExceeded }","typeGuard":"func isSizeExceeded(err error) bool { return errors.Is(err, tool.ErrExtractSizeExceeded) }","tryCatchPattern":"err := extractor.Extract(ctx, archive, limiter)\nif errors.Is(err, tool.ErrExtractSizeExceeded) {\n    // do not retry blindly: either raise the cap for trusted archives or reject\n    return rejectOrEscalate(archive)\n}","preventionTips":["List entries and sum declared sizes before extracting","Set caps in unambiguous units (bytes) and document them","Treat limit trips on untrusted uploads as security events, not bugs"],"tags":["archive","security","decompression-bomb","limits","go"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}