{"record":{"id":"19a519269ffe0324","repo":"can1357/oh-my-pi","slug":"asar-member-formatarchivepathforerror-memberpat","errorCode":null,"errorMessage":"ASAR member '${formatArchivePathForError(memberPath)}' failed SHA256 integrity verification","messagePattern":"ASAR member '(.+?)' failed SHA256 integrity verification","errorType":"exception","errorClass":"ArchiveError","httpStatus":null,"severity":"critical","filePath":"packages/utils/src/ar/asar.ts","lineNumber":96,"sourceCode":"\t\tthrow invalidAsar(`file '${label}' has invalid integrity blocks`);\n\t}\n\tconst expectedBlocks = Math.max(1, Math.ceil(size / value.blockSize));\n\tif (value.blocks.length !== expectedBlocks) {\n\t\tthrow invalidAsar(`file '${label}' has an inconsistent integrity block count`);\n\t}\n\tfor (const block of value.blocks) {\n\t\tif (typeof block !== \"string\" || !SHA256_HEX.test(block)) {\n\t\t\tthrow invalidAsar(`file '${label}' has an invalid integrity block hash`);\n\t\t}\n\t}\n\treturn { algorithm: \"SHA256\", hash: value.hash.toLowerCase() };\n}\n\nfunction verifyIntegrity(bytes: Uint8Array, integrity: AsarIntegrity | undefined, memberPath: string): void {\n\tif (!integrity) return;\n\tconst actual = new Bun.CryptoHasher(\"sha256\").update(bytes).digest(\"hex\");\n\tif (actual !== integrity.hash) {\n\t\tthrow new ArchiveError(\n\t\t\t`ASAR member '${formatArchivePathForError(memberPath)}' failed SHA256 integrity verification`,\n\t\t);\n\t}\n}\n\nclass PackedAsarMemberSource implements MemberSource {\n\treadonly #source: ByteSource;\n\treadonly #offset: number;\n\treadonly #size: number;\n\treadonly #integrity?: AsarIntegrity;\n\n\tconstructor(source: ByteSource, offset: number, size: number, integrity: AsarIntegrity | undefined) {\n\t\tthis.#source = source;\n\t\tthis.#offset = offset;\n\t\tthis.#size = size;\n\t\tthis.#integrity = integrity;\n\t}\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/ar/asar.ts#L78-L114","documentation":"ASAR archives embed a SHA256 hash for each member in the header's integrity block. After reading a member's bytes, verifyIntegrity recomputes the hash with Bun.CryptoHasher and compares it to the recorded hash. A mismatch means the member bytes differ from what was packed — corruption, tampering, or an out-of-sync header — so the read is aborted.","triggerScenarios":"The ASAR read path (member read → verifyIntegrity) computes sha256 of the extracted bytes and it does not equal the integrity.hash recorded in the ASAR header for that memberPath. Only fires when the header actually carries an integrity entry (no integrity → check skipped).","commonSituations":"ASAR file modified after signing (manual edits, patchers, malware); truncated or bit-rotted files; a repacked header paired with stale member data; MITM/corrupted downloads of Electron app resources.","solutions":["Re-obtain the ASAR file from a trusted source and verify the whole-file checksum first; integrity failure usually means the file itself is bad.","Do NOT bypass the check if the file is untrusted — a mismatch is the designed tamper signal.","If you legitimately repacked the ASAR, regenerate it with the official asar tool so header hashes match member data.","Confirm no post-processing step (minifier, antivirus quarantine/restore, sync tool) is rewriting member bytes after packaging."],"exampleFix":"// before\nconst bytes = await member.read(size, path); // throws on hash mismatch\n// after\ntry {\n  const bytes = await member.read(size, path);\n} catch (e) {\n  if (e instanceof ArchiveError && e.message.includes(\"integrity verification\")) {\n    const fresh = await reDownloadTrustedAsar(url);\n    return readMember(fresh, path);\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Verify the whole ASAR file against a publisher-provided checksum before any member read.\nconst whole = createHash(\"sha256\").update(asarBytes).digest(\"hex\");\nif (expectedFileSha256 && whole !== expectedFileSha256) {\n\tthrow new Error(\"ASAR file does not match publisher checksum; refusing to read\");\n}","typeGuard":"function hasIntegrityEntry(entry: AsarHeaderEntry): entry is AsarHeaderEntry & { integrity: AsarIntegrity } {\n\treturn typeof (entry as { integrity?: unknown }).integrity === \"object\" && entry.integrity !== null && typeof entry.integrity.hash === \"string\";\n}","tryCatchPattern":"try {\n\tconst bytes = await member.read(size, path);\n} catch (e) {\n\tif (e instanceof ArchiveError && e.message.includes(\"failed SHA256 integrity verification\")) {\n\t\t// tamper/corruption signal: quarantine the file, do not retry in place\n\t\tawait quarantine(asarPath);\n\t\tthrow new SecurityError(`ASAR tampering detected in ${path}`);\n\t}\n\tthrow e;\n}","preventionTips":["Never bypass or strip integrity entries on untrusted ASAR files — the mismatch is the tamper signal.","Verify publisher whole-file checksums/signatures before parsing.","Regenerate ASARs with the official asar tool after any legitimate edit so hashes stay in sync.","Watch for post-packaging processes (AV, sync, minifiers) that rewrite member bytes."],"tags":["archive","asar","integrity","sha256","tampering"],"backgroundTag":"checksum-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}