{"record":{"id":"ee62b495e5c0d372","repo":"chatboxai/chatbox","slug":"zip-archive-compression-ratio-is-unsafe","errorCode":null,"errorMessage":"ZIP archive compression ratio is unsafe","messagePattern":"ZIP archive compression ratio is unsafe","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/renderer/packages/backup/zip.ts","lineNumber":301,"sourceCode":"  try {\n    while (true) {\n      throwIfAborted(options.signal)\n      const { done, value } = await reader.read()\n      if (done) {\n        unzip.push(EMPTY_BYTES, true)\n        break\n      }\n      unzip.push(value)\n      if (fatalError) throw fatalError\n      if (pendingHandlers.length > 0) await Promise.all(pendingHandlers.splice(0))\n    }\n    if (fatalError) throw fatalError\n    if (pendingHandlers.length > 0) await Promise.all(pendingHandlers.splice(0))\n    if (\n      totalUncompressedBytes > 1024 * 1024 &&\n      totalUncompressedBytes > Math.max(1, file.size) * limits.maxCompressionRatio\n    ) {\n      throw new Error('ZIP archive compression ratio is unsafe')\n    }\n  } finally {\n    await reader.cancel().catch(() => undefined)\n  }\n}\n","sourceCodeStart":283,"sourceCodeEnd":307,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/packages/backup/zip.ts#L283-L307","documentation":"Whole-archive zip-bomb guard evaluated after all entries have streamed: thrown when totalUncompressedBytes exceeds 1 MiB AND exceeds Math.max(1, file.size) * limits.maxCompressionRatio (default 2000x). Unlike the per-entry check, this uses the cumulative decompressed byte count tracked across every entry's ondata chunks.","triggerScenarios":"An archive whose aggregate decompressed size is >2000x its on-disk size, achievable via many moderate-ratio entries that each pass the per-entry check, or a single entry that narrowly skirted it.","commonSituations":"Multi-entry zip-bombs, archives of highly compressible generated data, or backups of sparse virtual-disk images.","solutions":["Raise limits.maxCompressionRatio for trusted backups known to compress well.","Reject the archive for untrusted sources; archive-level >2000x compression is rarely benign.","Re-export excluding redundant/highly-compressible payloads."],"exampleFix":"// before\nawait readZipFileEntries(file, onEntry)\n\n// after: raise the archive-level ratio cap for a trusted source\nawait readZipFileEntries(file, onEntry, {\n  limits: { maxCompressionRatio: 5_000 }\n})","handlingStrategy":"validation","validationCode":"// Raise the archive-level ratio cap for a trusted, highly-compressible source.\nawait readZipFileEntries(file, onEntry, {\n  limits: { maxCompressionRatio: 5_000 },\n})","typeGuard":null,"tryCatchPattern":"try {\n  await readZipFileEntries(file, onEntry, opts)\n} catch (error) {\n  if (error instanceof Error && error.message === 'ZIP archive compression ratio is unsafe') {\n    reportToUser('This archive is likely a zip-bomb and was rejected.')\n  } else throw error\n}","preventionTips":["Treat an archive-level ratio over 2000x as a zip-bomb for untrusted sources.","Only raise the cap for your own exporter whose output you know compresses well.","Combine with maxTotalUncompressedBytes as a second bound."],"tags":["zip","backup","zip-bomb","limits","security"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}