{"record":{"id":"92a2c96f8a16e30c","repo":"JuliusBrussee/caveman","slug":"signed-checksum-manifest-is-malformed","errorCode":null,"errorMessage":"signed checksum manifest is malformed","messagePattern":"signed checksum manifest is malformed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/shared/binary-installer/installer.mjs","lineNumber":121,"sourceCode":"    const digest = createHash(\"sha256\").update(checksums).digest();\n    const bundled = Buffer.from(bundle.messageSignature.messageDigest.digest, \"base64\");\n    if (digest.length !== bundled.length || !digest.equals(bundled)) return false;\n    return verify(\n      \"sha256\",\n      Buffer.from(checksums),\n      createPublicKey(BINARY_SIGNING_PUBKEY),\n      Buffer.from(bundle.messageSignature.signature, \"base64\"),\n    );\n  } catch {\n    return false;\n  }\n}\n\nfunction expectedDigest(checksums, artifact) {\n  for (const line of checksums.split(\"\\n\")) {\n    if (!line) continue;\n    const match = line.match(/^([a-f0-9]{64})  ([A-Za-z0-9._-]+)$/);\n    if (!match) throw new Error(\"signed checksum manifest is malformed\");\n    if (match[2] === artifact) return match[1];\n  }\n  throw new Error(`signed checksum manifest does not contain ${artifact}`);\n}\n\nfunction cleanup(path) {\n  try {\n    unlinkSync(path);\n  } catch (error) {\n    if (error.code !== \"ENOENT\") throw error;\n  }\n}\n\nasync function download(url, part, timeout) {\n  const response = await asset(url, timeout);\n  if (!response.body) throw new Error(\"binary download failed: response body missing\");\n  const hash = createHash(\"sha256\");\n  const file = await open(part, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/shared/binary-installer/installer.mjs#L103-L139","documentation":"expectedDigest() in the binary installer parses the signature-verified checksums.txt line by line against a strict '<64 lowercase hex>  <safe filename>' format (two spaces). A line that is present but does not match — bad hash casing or length, tab separator, carriage-return residue, odd filename characters — makes the whole manifest untrustworthy, so parsing aborts even though the signature checked out.","triggerScenarios":"A republished or repacked release where checksums.txt was regenerated with a different tool (different sha256sum flags, CRLF line endings, uppercase hex); a mirror rewriting files; a genuinely tampered manifest that happens to carry a valid signature over corrupted content.","commonSituations":"Internal mirrors that normalize line endings; release pipelines switching checksum tools; manual edits to checksums.txt; partial file truncation.","solutions":["If you control the release: regenerate checksums.txt with standard sha256sum output (lowercase hex, two spaces, LF endings)","If consuming: unset CAVE_BINARY_RELEASE_BASE to pull the official manifest, and report the bad mirror or artifact upstream","Never hand-edit checksums.txt to make parsing pass — the format rejection is a tamper signal"],"exampleFix":"# before (malformed: uppercase hex, tab separator)\n# 0A1B…F\tcaveman-mcp_linux_amd64\n\n# after\ncd artifacts && sha256sum * > ../checksums.txt   # lowercase hex, two spaces","handlingStrategy":"validation","validationCode":"// validate a manifest your pipeline produces, before publishing\nfor (const line of checksums.split(\"\\n\")) {\n  if (line && !/^([a-f0-9]{64})  ([A-Za-z0-9._-]+)$/.test(line)) {\n    throw new Error(`malformed checksum line: ${JSON.stringify(line)}`);\n  }\n}","typeGuard":"function isValidChecksumLine(line) {\n  return /^([a-f0-9]{64})  ([A-Za-z0-9._-]+)$/.test(line);\n}","tryCatchPattern":"try { await ensureBinary({ name, envVar }); }\ncatch (e) {\n  if (/signed checksum manifest is malformed/.test(String(e?.message))) {\n    delete process.env.CAVE_BINARY_RELEASE_BASE; // retry against the official host\n    return ensureBinary({ name, envVar });\n  }\n  throw e;\n}","preventionTips":["Generate manifests with plain sha256sum (lowercase hex, two spaces, LF) and never edit them by hand","Never loosen parsing to get past this error — it is a tamper signal"],"tags":["security","installer","checksum"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}