{"record":{"id":"3f7717a29cdac016","repo":"chatboxai/chatbox","slug":"zip-contains-too-many-entries","errorCode":null,"errorMessage":"ZIP contains too many entries","messagePattern":"ZIP contains too many entries","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/renderer/packages/backup/zip.ts","lineNumber":227,"sourceCode":"  onEntry: (entry: ReadZipEntry) => Promise<void> | void,\n  options: ZipReadOptions = {}\n): Promise<void> {\n  await validateZipEndOfCentralDirectory(file)\n  const limits = { ...DEFAULT_ZIP_LIMITS, ...options.limits }\n  const seenPaths = new Set<string>()\n  const pendingHandlers: Promise<void>[] = []\n  let entryCount = 0\n  let totalUncompressedBytes = 0\n  let fatalError: unknown\n\n  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) {","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/packages/backup/zip.ts#L209-L245","documentation":"Thrown after incrementing entryCount when it exceeds limits.maxEntries (default 100,004 from DEFAULT_ZIP_LIMITS). It is a zip-bomb / resource-exhaustion guard that aborts streaming before the archive can enumerate an attacker-controlled or pathologically large number of entries.","triggerScenarios":"An archive with more than 100,004 entries, or with more than a caller-lowered maxEntries. Trips as soon as the (entryCount+1)-th entry callback fires.","commonSituations":"Legitimate large backups (e.g. node_modules or many small chat-attachment files) that breach the default, hostile test archives, or an integration that set limits.maxEntries too low.","solutions":["Pass a higher limits.maxEntries in ZipReadOptions if the archive is trusted and known large.","Re-export the backup excluding unnecessary tiny files to shrink the entry count.","Keep the default cap for untrusted imports and surface a clear 'too many files' message to the user."],"exampleFix":"// before\nawait readZipFileEntries(file, onEntry)\n\n// after: raise the cap for trusted full backups\nawait readZipFileEntries(file, onEntry, {\n  limits: { maxEntries: 500_000 }\n})","handlingStrategy":"validation","validationCode":"// Configure the cap to match the trusted archive's known entry count.\nconst options: ZipReadOptions = {\n  limits: { maxEntries: 500_000 }, // raise for trusted full backups\n}\nawait readZipFileEntries(file, onEntry, options)","typeGuard":null,"tryCatchPattern":"try {\n  await readZipFileEntries(file, onEntry, { limits: { maxEntries } })\n} catch (error) {\n  if (error instanceof Error && error.message === 'ZIP contains too many entries') {\n    // Either raise the cap (trusted) or reject (untrusted).\n  } else throw error\n}","preventionTips":["Pick limits.maxEntries based on whether the source is trusted (your exporter) or untrusted (user upload).","Keep the conservative default for untrusted imports and surface a clear message.","Exclude unnecessary tiny files (e.g. node_modules) at export time to keep entry counts sane."],"tags":["zip","backup","limits","zip-bomb","resource-exhaustion"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}