{"record":{"id":"a1b78f0e31ae08f0","repo":"can1357/oh-my-pi","slug":"invalid-cpio-archive-field-is-too-large","errorCode":null,"errorMessage":"Invalid CPIO archive: ${field} is too large","messagePattern":"Invalid CPIO archive: (.+?) is too large","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/cpio.ts","lineNumber":117,"sourceCode":"\t) {\n\t\tthrow new ArchiveError(`Invalid CPIO archive: truncated ${what}`);\n\t}\n}\n\nfunction parseDigits(bytes: Uint8Array, offset: number, length: number, radix: 8 | 16, field: string): number {\n\trequireRange(bytes, offset, offset + length, `${field} field`);\n\tlet value = 0;\n\tfor (let index = offset; index < offset + length; index++) {\n\t\tconst code = bytes[index]!;\n\t\tlet digit: number;\n\t\tif (code >= 0x30 && code <= 0x39) digit = code - 0x30;\n\t\telse if (radix === 16 && code >= 0x41 && code <= 0x46) digit = code - 0x41 + 10;\n\t\telse if (radix === 16 && code >= 0x61 && code <= 0x66) digit = code - 0x61 + 10;\n\t\telse throw new ArchiveError(`Invalid CPIO archive: ${field} is not a valid base-${radix} number`);\n\t\tif (digit >= radix) throw new ArchiveError(`Invalid CPIO archive: ${field} is not a valid base-${radix} number`);\n\t\tvalue = value * radix + digit;\n\t}\n\tif (!Number.isSafeInteger(value)) throw new ArchiveError(`Invalid CPIO archive: ${field} is too large`);\n\treturn value;\n}\n\nfunction parseHeader(bytes: Uint8Array, offset: number): ParsedHeader {\n\trequireRange(bytes, offset, offset + 2, \"header\");\n\tconst first = bytes[offset]!;\n\tconst second = bytes[offset + 1]!;\n\tif ((first === 0xc7 && second === 0x71) || (first === 0x71 && second === 0xc7)) {\n\t\trequireRange(bytes, offset, offset + BINARY_HEADER_SIZE, \"old binary header\");\n\t\tconst littleEndian = first === 0xc7;\n\t\tconst read16 = littleEndian ? readUInt16LE : readUInt16BE;\n\t\tconst read32Words = (fieldOffset: number): number =>\n\t\t\tread16(bytes, offset + fieldOffset) * 0x10000 + read16(bytes, offset + fieldOffset + 2);\n\t\treturn {\n\t\t\theaderSize: BINARY_HEADER_SIZE,\n\t\t\talignment: 2,\n\t\t\tdevMajor: 0,\n\t\t\tdevMinor: read16(bytes, offset + 2),","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/cpio.ts#L99-L135","documentation":"After successfully decoding all digits of a header field, parseDigits checks Number.isSafeInteger on the accumulated value and throws ArchiveError if the field exceeds Number.MAX_SAFE_INTEGER. CPIO numeric fields are fixed-width ASCII, so a pathological or hostile archive can encode values (e.g. a 16-hex-digit newc field) larger than 2^53-1; the library refuses rather than silently losing precision in sizes, offsets, or inode values.","triggerScenarios":"Parsing a newc/new ASCII CPIO whose 8-hex-char field is at its maximum (0xFFFFFFFF = 4294967295 is safe, but wider/degenerate inputs or accumulated offsets produce unsafe values) — practically, archives with absurd file sizes, name sizes, or checksums near 2^53+; crafted/fuzzed headers with all-'F' or digit-saturated fields combined with wide field interpretations.","commonSituations":"Maliciously crafted or fuzzed archives (security scanning pipelines); corruption that turns padding into digit bytes inflating a field; tools writing 64-bit values into fields this parser reads as wider ASCII spans.","solutions":["Inspect the offending field bytes and re-create the archive with sane values using standard cpio tooling","If this comes from an RPM payload, rebuild the package — real archives never have unsafe field values","Treat the archive as untrusted/corrupt and reject it upstream; this error is a tamper indicator","Check you are not double-reading or concatenating archives such that a later entry's digits run together"],"exampleFix":"// before: trusting an untrusted cpio blob wholesale\nconst entries = await readCpio(untrustedSource, options);\n// after: reject obviously oversized declarations up front\nif (untrustedSource.size > 2 ** 32) throw new Error('implausible archive size');\ntry {\n  const entries = await readCpio(untrustedSource, options);\n} catch (e) {\n  if (e instanceof ArchiveError) quarantine(e);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// plausibility check before parsing untrusted input\nif (source.size > 2 ** 32) throw new Error('archive implausibly large for a CPIO payload');","typeGuard":null,"tryCatchPattern":"try {\n  const entries = await readCpio(source, options);\n} catch (err) {\n  if (err instanceof ArchiveError && err.message.includes('is too large')) {\n    // unsafe integer in header field: quarantine input, do not retry\n  } else throw err;\n}","preventionTips":["Treat 'too large' header values from untrusted sources as tamper indicators","Cap input size before parsing via reader limits (assertInMemorySize options)","Avoid concatenating multiple cpio streams where trailing digits could inflate a field","Regenerate archives with standard tooling; legit fields never exceed 32 bits"],"tags":["archive","cpio","integer-overflow","security"],"backgroundTag":"integer-overflow","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}