{"record":{"id":"5ceb3c30f9ff55be","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-cfheader-reserve-area-exceeds","errorCode":null,"errorMessage":"Invalid CAB archive: CFHEADER reserve area exceeds 60000 bytes","messagePattern":"Invalid CAB archive: CFHEADER reserve area exceeds 60000 bytes","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cab.ts","lineNumber":279,"sourceCode":"\tconst folderCount = readUInt16LE(fixed, 26);\n\tconst fileCount = readUInt16LE(fixed, 28);\n\tconst flags = readUInt16LE(fixed, 30);\n\tif (flags & 0x0003) throw new ArchiveError(\"Unsupported multi-volume CAB archive (previous/next cabinet link)\");\n\tassertEntryCount(folderCount + fileCount, options.limits);\n\tif (folderCount === 0 && fileCount !== 0)\n\t\tthrow new ArchiveError(\"Invalid CAB archive: files exist without a folder\");\n\n\tlet headerReserveSize = 0;\n\tlet folderReserveSize = 0;\n\tlet dataReserveSize = 0;\n\tlet folderTableOffset = FIXED_HEADER_SIZE;\n\tif (flags & 0x0004) {\n\t\tconst reserveHeader = await readExact(source, FIXED_HEADER_SIZE, FIXED_HEADER_SIZE + 4, cabinetSize);\n\t\theaderReserveSize = readUInt16LE(reserveHeader, 0);\n\t\tfolderReserveSize = reserveHeader[2]!;\n\t\tdataReserveSize = reserveHeader[3]!;\n\t\tif (headerReserveSize > 60_000)\n\t\t\tthrow new ArchiveError(\"Invalid CAB archive: CFHEADER reserve area exceeds 60000 bytes\");\n\t\tfolderTableOffset += 4 + headerReserveSize;\n\t}\n\tconst folderRecordSize = 8 + folderReserveSize;\n\tconst folderTableEnd = folderTableOffset + folderCount * folderRecordSize;\n\tif (!Number.isSafeInteger(folderTableEnd) || folderTableEnd > cabinetSize || folderTableEnd > fileTableOffset) {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: CFFOLDER table is out of bounds\");\n\t}\n\tassertIndexSize(folderTableEnd, options.limits, \"CAB header\");\n\tconst header = await readExact(source, 0, folderTableEnd, cabinetSize);\n\tconst descriptions: CabFolderDescription[] = [];\n\tfor (let index = 0; index < folderCount; index++) {\n\t\tconst offset = folderTableOffset + index * folderRecordSize;\n\t\tconst type = readUInt16LE(header, offset + 6);\n\t\tdescriptions.push({\n\t\t\tdataStart: readUInt32LE(header, offset),\n\t\t\tdataEnd: cabinetSize,\n\t\t\tblockCount: readUInt16LE(header, offset + 4),\n\t\t\tmethod: type & 0x000f,","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cab.ts#L261-L297","documentation":"When CFHEADER flags has 0x0004 set, a reserve area follows the fixed header; its header-reserve length is a 16-bit field (cbCFHeader). The CAB spec limits this to 60000 bytes, and the library enforces that ceiling to bound how far the folder table can be pushed into the file.","triggerScenarios":"Calling readCab() on a reserved-area CAB (flags & 0x0004) whose cbCFHeader field exceeds 60000 — essentially only possible in crafted/fuzzed files or archives using the ABNORMAL reserve layout (e.g. someInstallShield variants) that exceed the spec limit.","commonSituations":"Malformed synthetic archives, fuzz test inputs, and rarely nonstandard packers abusing the reserve area beyond the specification's 60000-byte cap.","solutions":["Treat the archive as non-conforming; obtain a compliant copy or extract it with a tolerant external tool first.","Hex-dump the reserve size at offset 36 (two bytes, LE) and confirm whether it truly exceeds 60000.","If produced by an in-house packer, clamp/limit the header reserve to <= 60000 bytes as the spec requires.","If the file uses an InstallShield-style abnormal layout, extract the inner cabinet and read that instead."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const buf = new Uint8Array(await Bun.file(path).arrayBuffer());\nconst flags = buf[30] | (buf[31]! << 8);\nif (flags & 0x0004) {\n\tconst cbCFHeader = buf[36] | (buf[37]! << 8);\n\tif (cbCFHeader > 60_000) throw new Error(`CAB header reserve ${cbCFHeader} exceeds spec limit of 60000`);\n}","typeGuard":null,"tryCatchPattern":"try {\n\tconst entries = await readCab(source);\n} catch (err) {\n\tif (err instanceof ArchiveError && err.message.includes(\"reserve area exceeds 60000\")) {\n\t\tthrow new Error(\"Non-conforming CAB reserve area; use an external extraction tool\", { cause: err });\n\t}\n\tthrow err;\n}","preventionTips":["Check the reserve size field when flags & 0x0004 is set, before parsing.","Clamp header reserve to <= 60000 bytes in CAB-producing code.","For InstallShield-style abnormal layouts, extract the inner cabinet first."],"tags":["archive","cab","reserve-area","limits"],"backgroundTag":"corrupt-archive-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}