{"record":{"id":"3b8caee1cc4ec124","repo":"can1357/oh-my-pi","slug":"invalid-lzh-extended-header-size","errorCode":null,"errorMessage":"Invalid LZH extended header size","messagePattern":"Invalid LZH extended header size","errorType":"validation","errorClass":"ArchiveError","httpStatus":null,"severity":"error","filePath":"packages/utils/src/ar/lzh.ts","lineNumber":509,"sourceCode":"\t\tif (level === 0) {\n\t\t\tconst extendedStart = offset + 24 + nameLength;\n\t\t\tif (baseEnd - extendedStart >= 12) {\n\t\t\t\tconst extended = bytes.subarray(extendedStart, baseEnd);\n\t\t\t\tif ((extended[0] === 0x55 || extended[0] === 0x4b) && extended[1] === 0) {\n\t\t\t\t\tosId = extended[0]!;\n\t\t\t\t\tfields.mtimeMs = u32(extended, 2) * 1000;\n\t\t\t\t\tfields.mode = u16(extended, extended.byteLength - 6);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdataStart = baseEnd;\n\t\t} else {\n\t\t\tosId = bytes[offset + 24 + nameLength]!;\n\t\t\tlet extensionSize = u16(bytes, baseEnd - 2);\n\t\t\tlet cursor = baseEnd;\n\t\t\tlet totalExtensionSize = 0;\n\t\t\tlet extensionCount = 0;\n\t\t\twhile (extensionSize !== 0) {\n\t\t\t\tif (extensionSize < 3) throw new ArchiveError(\"Invalid LZH extended header size\");\n\t\t\t\tassertRange(bytes, cursor, cursor + extensionSize, \"extended header\");\n\t\t\t\ttotalExtensionSize += extensionSize;\n\t\t\t\tassertIndexSize(headerLength + 2 + totalExtensionSize, options.limits, \"header metadata\");\n\t\t\t\tif (++extensionCount > 65_535) throw new ArchiveError(\"Invalid LZH archive: too many extended headers\");\n\t\t\t\tconst type = bytes[cursor]!;\n\t\t\t\tconst dataEnd = cursor + extensionSize - 2;\n\t\t\t\tconst data = bytes.subarray(cursor + 1, dataEnd);\n\t\t\t\tif (type === 0x01 || type === 0x02 || type === 0x44 || type === 0x45) {\n\t\t\t\t\tassertArchivePathBytes(data.byteLength, \"member path\", options.limits.maxPathBytes);\n\t\t\t\t}\n\t\t\t\tprocessExtendedHeader(type, data, cursor + 1, fields);\n\t\t\t\tconst currentSize = extensionSize;\n\t\t\t\textensionSize = u16(bytes, dataEnd);\n\t\t\t\tcursor += currentSize;\n\t\t\t}\n\t\t\tdataStart = baseEnd + totalExtensionSize;\n\t\t\tpackedSize = fields.packedSize ?? packedSize - totalExtensionSize;\n\t\t\tif (packedSize < 0) throw new ArchiveError(\"Invalid LZH level-1 packed size\");","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/lzh.ts#L491-L527","documentation":"Thrown while walking a level-1 LZH header's chain of extended headers when an extension records a size smaller than the 3-byte minimum (2-byte size field + 1 type byte). Such a record cannot exist in the format, so the header chain is corrupt.","triggerScenarios":"Parsing an archive whose extended-header chain contains a zero-corrupted or miscomputed size field, or where a prior extension's size was wrong so the cursor lands mid-field.","commonSituations":"Damaged archives, non-conforming writers, or fuzzed inputs exercising the extension-chain loop.","solutions":["Obtain an intact copy of the archive","Repack with a conforming LHA tool","Reject the file if input is untrusted — the chain is unrecoverable without heuristics"],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { parse(); } catch (err) { if (err instanceof ArchiveError && err.message.includes('extended header')) reject(err); else throw err; }","preventionTips":["Avoid level-1 archives when possible","Fuzz-test your ingestion path"],"tags":["archive","lzh","extended-header","malformed"],"backgroundTag":"corrupt-archive-header","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}