{"record":{"id":"0dcb61efd71faf65","repo":"can1357/oh-my-pi","slug":"invalid-cab-archive-member-memberpath-is-out","errorCode":null,"errorMessage":"Invalid CAB archive: member '${memberPath}' is outside its folder data","messagePattern":"Invalid CAB archive: member '(.+?)' is outside its folder data","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cab.ts","lineNumber":232,"sourceCode":"\t\t}\n\t\treturn output;\n\t}\n}\n\nclass CabMemberSource implements MemberSource {\n\treadonly #folder: CabFolder;\n\treadonly #offset: number;\n\treadonly #declaredSize: number;\n\n\tconstructor(folder: CabFolder, offset: number, size: number) {\n\t\tthis.#folder = folder;\n\t\tthis.#offset = offset;\n\t\tthis.#declaredSize = size;\n\t}\n\n\tasync read(size: number, memberPath: string): Promise<Uint8Array> {\n\t\tif (size !== this.#declaredSize) {\n\t\t\tthrow new ArchiveError(`Invalid CAB archive: size changed while extracting '${memberPath}'`);\n\t\t}\n\t\tconst folder = await this.#folder.readAll();\n\t\tconst end = this.#offset + size;\n\t\tif (!Number.isSafeInteger(end) || this.#offset < 0 || end > folder.byteLength) {\n\t\t\tthrow new ArchiveError(`Invalid CAB archive: member '${memberPath}' is outside its folder data`);\n\t\t}\n\t\treturn folder.slice(this.#offset, end);\n\t}\n}\n\nasync function readCabArchive(source: ByteSource, options: Parameters<FormatReader>[1]): Promise<ArchiveIndexEntry[]> {\n\tif (source.size < FIXED_HEADER_SIZE) throw new ArchiveError(\"Invalid CAB archive: truncated CFHEADER\");\n\tconst fixed = await readExact(source, 0, FIXED_HEADER_SIZE);\n\tif (!hasSignature(fixed)) throw new ArchiveError(`Invalid CAB archive: expected ${CAB_SIGNATURE} signature`);\n\tif (readUInt32LE(fixed, 4) !== 0 || readUInt32LE(fixed, 12) !== 0 || readUInt32LE(fixed, 20) !== 0) {\n\t\tthrow new ArchiveError(\"Invalid CAB archive: reserved CFHEADER fields must be zero\");\n\t}\n\tconst cabinetSize = readUInt32LE(fixed, 8);","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cab.ts#L214-L250","documentation":"Thrown by CabMemberSource.read when the member's [offset, offset+size) range falls outside the folder's fully decoded byte buffer — negative offset, unsafe integer overflow, or an end past the folder length. This catches cabinets whose CFFILE folderOffset/size point outside the actual folder data, preventing out-of-range slices.","triggerScenarios":"readCab() indexed a malformed cabinet where a CFFILE entry's folderOffset+usize exceeds the folder's decoded output length (or offset is negative/end overflows); also reachable if folder data decoded shorter than the file table implied without tripping the requiredSize check.","commonSituations":"Malformed or corrupted cabinets; crafted archives from untrusted sources; archives produced by buggy writers with wrong CFFILE offsets.","solutions":["Validate the archive with `cabextract -t` or 7-Zip; if they reject it, the file is malformed — obtain a good copy","If you generate cabinets, ensure each CFFILE's folderOffset+size stays within the folder's total decompressed bytes","Treat this as a signal when processing untrusted archives: catch ArchiveError and reject the file rather than attempting repair","If a standard tool accepts the file but this reader throws, file a bug with the repro archive"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// reject malformed cabinets up front with an independent parser\nconst t = Bun.$`cabextract -t ${path}`.quiet().nothrow();\nif ((await t).exitCode !== 0) throw new Error(`malformed cabinet: ${path}`);","typeGuard":null,"tryCatchPattern":"try {\n  await readCab(source, opts);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('outside its folder data'))\n    throw new Error('Cabinet member offsets point outside folder data — file is malformed.');\n  throw err;\n}","preventionTips":["Only extract from trusted or pre-validated cabinets","Treat this error on untrusted input as a hard rejection, not a recoverable state","Keep cabinets unmodified between production and consumption"],"tags":["archive","cab","bounds","malformed"],"backgroundTag":"archive-structure-invalid","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}