{"record":{"id":"01389e02b3369701","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-metadata-range-is-out-of-boun","errorCode":null,"errorMessage":"Invalid CAB archive: metadata range is out of bounds","messagePattern":"Invalid CAB archive: metadata range is out of bounds","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cab.ts","lineNumber":43,"sourceCode":"const LEGACY_NAME_DECODER = new TextDecoder(\"windows-1252\");\n\ninterface CabFolderDescription {\n\tdataStart: number;\n\tdataEnd: number;\n\tblockCount: number;\n\tmethod: number;\n\tparameter: number;\n\trequiredSize: number;\n}\n\nasync function readExact(\n\tsource: ByteSource,\n\tstart: number,\n\tend: number,\n\tcabinetSize = source.size,\n): Promise<Uint8Array> {\n\tif (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start || end > cabinetSize) {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: metadata range is out of bounds\");\n\t}\n\tlet bytes: Uint8Array;\n\ttry {\n\t\tbytes = await source.read(start, end);\n\t} catch (error) {\n\t\tif (error instanceof ArchiveError) throw error;\n\t\tthrow new ArchiveError(`Unable to read CAB archive: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tif (bytes.byteLength !== end - start) throw new ArchiveError(\"Invalid CAB archive: truncated data\");\n\treturn bytes;\n}\n\nfunction hasSignature(bytes: Uint8Array): boolean {\n\treturn bytes.byteLength >= 4 && bytes[0] === 0x4d && bytes[1] === 0x53 && bytes[2] === 0x43 && bytes[3] === 0x46;\n}\n\nfunction cabChecksum(bytes: Uint8Array, initial = 0): number {\n\tlet checksum = initial >>> 0;","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cab.ts#L25-L61","documentation":"readExact is CAB's guard for every metadata read: it validates that [start, end) is a sane range — safe integers, non-negative, ordered, and within the cabinet's size — before issuing the read. This rejects CAB files whose header/folder/file-table fields point outside the file (common with corruption or crafted archives), converting them into a uniform ArchiveError instead of an I/O error downstream.","triggerScenarios":"Parsing a CAB whose CFFOLDER/CFFILE offsets or cbCabinet sizes exceed the actual file size; a truncated cabinet where declared metadata runs past EOF; an offset read at a misaligned position after earlier parse drift; passing an explicit cabinetSize argument smaller than the ranges being requested.","commonSituations":"Partially downloaded or truncated .cab files; corrupted Windows update payloads; malicious archives with inflated offset fields; mounting archives through a ByteSource whose `size` disagrees with the real content length.","solutions":["Verify the file is complete — compare actual byte length against the declared cbCabinet in the CFHEADER and re-download if truncated.","Check the ByteSource's `size` reflects the real file size; a wrong size makes valid ranges look out of bounds.","Inspect the offsets being requested; if they grow implausibly during parsing, earlier structure parsing is likely misaligned.","Treat the cabinet as invalid/corrupt and refuse to process it — the library intentionally refuses partial metadata reads."],"exampleFix":"// before\nconst table = await readExact(source, fileTableOffset, fileTableOffset + tableSize); // throws if offset+size > source.size\n// after\nif (fileTableOffset + tableSize > source.size) {\n  throw new Error(`truncated cabinet: file table ends at ${fileTableOffset + tableSize} but file is ${source.size} bytes`);\n}\nconst table = await readExact(source, fileTableOffset, fileTableOffset + tableSize);","handlingStrategy":"try-catch","validationCode":"function isReadableRange(start, end, cabinetSize) {\n  return Number.isSafeInteger(start) && Number.isSafeInteger(end) &&\n    start >= 0 && end >= start && end <= cabinetSize;\n}\n// before reading metadata:\nif (!isReadableRange(fileTableOffset, fileTableOffset + tableSize, source.size)) {\n  throw new Error(\"cabinet metadata out of bounds — file likely truncated or corrupt\");\n}","typeGuard":"function isSafeRange(start, end, limit) {\n  return Number.isSafeInteger(start) && Number.isSafeInteger(end) &&\n    start >= 0 && end >= start && end <= limit;\n}","tryCatchPattern":"try {\n  const header = await readExact(source, 0, 42);\n} catch (err) {\n  if (err instanceof ArchiveError) {\n    if (err.message.includes(\"out of bounds\")) throw new Error(\"invalid or truncated CAB archive\");\n    if (err.message.includes(\"truncated data\")) throw new Error(\"CAB file is incomplete\");\n  }\n  throw err;\n}","preventionTips":["Check file size against the CFHEADER cbCabinet field before parsing folders/entries.","Validate every offset read from the header lies within the file before dereferencing it.","Handle partial downloads: verify checksums or total length before extraction.","Never trust offsets from untrusted archives without bounding them to source.size."],"tags":["cab","archive","bounds-check","corrupt-file"],"backgroundTag":"archive-metadata-out-of-bounds","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}