{"record":{"id":"c3404f3f3222cd81","repo":"chatboxai/chatbox","slug":"zip-entry-compression-ratio-is-unsafe-entry-nam","errorCode":null,"errorMessage":"ZIP entry compression ratio is unsafe: ${entry.name}","messagePattern":"ZIP entry compression ratio is unsafe: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/renderer/packages/backup/zip.ts","lineNumber":238,"sourceCode":"  const unzip = new Unzip((entry) => {\n    try {\n      throwIfAborted(options.signal)\n      assertSafeArchivePath(entry.name)\n      if (seenPaths.has(entry.name)) throw new Error(`Duplicate ZIP entry: ${entry.name}`)\n      seenPaths.add(entry.name)\n      entryCount++\n      if (entryCount > limits.maxEntries) throw new Error('ZIP contains too many entries')\n      const entryLimits = { ...limits, ...options.entryLimits?.(entry.name) }\n      if (entry.originalSize !== undefined && entry.originalSize > entryLimits.maxEntryUncompressedBytes) {\n        throw new Error(`ZIP entry is too large: ${entry.name}`)\n      }\n      if (\n        entry.size !== undefined &&\n        entry.originalSize !== undefined &&\n        entry.originalSize > 1024 * 1024 &&\n        entry.originalSize > Math.max(1, entry.size) * entryLimits.maxCompressionRatio\n      ) {\n        throw new Error(`ZIP entry compression ratio is unsafe: ${entry.name}`)\n      }\n\n      const chunks: Uint8Array[] = []\n      let entryBytes = 0\n      entry.ondata = (error, data, final) => {\n        if (fatalError) return\n        if (error) {\n          fatalError = error\n          return\n        }\n        entryBytes += data.length\n        totalUncompressedBytes += data.length\n        if (entryBytes > entryLimits.maxEntryUncompressedBytes) {\n          fatalError = new Error(`ZIP entry is too large: ${entry.name}`)\n          entry.terminate()\n          return\n        }\n        if (totalUncompressedBytes > limits.maxTotalUncompressedBytes) {","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/packages/backup/zip.ts#L220-L256","documentation":"Per-entry zip-bomb guard: thrown when the entry's declared uncompressed size exceeds 1 MiB AND exceeds Math.max(1, entry.size) * entryLimits.maxCompressionRatio (default 2000x). It catches a small compressed payload that would balloon on inflation, using the header sizes so it fires before the data callback streams much content.","triggerScenarios":"A highly compressible entry (e.g. repeated bytes) whose compressed size is tiny relative to its uncompressed size, or a deliberately crafted zip-bomb entry.","commonSituations":"Test/security zip-bombs, log files full of repetition, or an exporter that compressed a sparse/padding-heavy blob.","solutions":["If high-ratio entries are legitimate for trusted paths, raise maxCompressionRatio via limits or entryLimits for those paths.","Reject the archive for untrusted imports; a >2000x ratio is almost always pathological.","Re-export without pathological padding/repetition on the producer side."],"exampleFix":"// before\nawait readZipFileEntries(file, onEntry)\n\n// after: raise the ratio cap for a trusted, highly-compressible log path\nawait readZipFileEntries(file, onEntry, {\n  entryLimits: (path) =>\n    path.endsWith('.log') ? { maxCompressionRatio: 10_000 } : {}\n})","handlingStrategy":"validation","validationCode":"// Raise maxCompressionRatio for trusted, highly-compressible paths only.\nawait readZipFileEntries(file, onEntry, {\n  entryLimits: (path) =>\n    path.endsWith('.log') ? { maxCompressionRatio: 10_000 } : {},\n})","typeGuard":null,"tryCatchPattern":"try {\n  await readZipFileEntries(file, onEntry, opts)\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('ZIP entry compression ratio is unsafe')) {\n    // For untrusted sources this is a zip-bomb: reject. For trusted logs, raise the cap.\n  } else throw error\n}","preventionTips":["Keep the default 2000x cap for untrusted archives; a higher ratio is almost always a zip-bomb.","Narrow ratio overrides to specific trusted paths (e.g. *.log).","Re-export without pathological padding/repetition on the producer side."],"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"}