JuliusBrussee/caveman · critical · Error
signature check failed for checksums.txt — refusing to insta
Error message
signature check failed for checksums.txt — refusing to install
What it means
ensureBinary() downloads checksums.txt plus its sigstore bundle (checksums.txt.keysig) and verifies the bundle's media type, the SHA-256 digest of the manifest, and an Ed25519 signature against the pinned BINARY_SIGNING_PUBKEY. If signedDigest() returns false for any reason, the installer refuses to proceed — no binary is downloaded from a release whose manifest provenance cannot be proven.
Source
Thrown at packages/shared/binary-installer/installer.mjs:178
}
const found = onPath(name);
if (found) return found;
const binDir = join(process.env.CAVEMAN_HOME ?? join(homedir(), ".caveman"), "bin");
const target = join(binDir, binaryInstallFilename(name));
if (executable(target)) return target;
const { os, arch } = targetPlatform();
const artifact = `${name}_${os}_${arch}`;
const base = (process.env.CAVE_BINARY_RELEASE_BASE ?? BINARY_RELEASE_BASE_DEFAULT).replace(/\/+$/, "");
const release = `${base}/${BINARY_RELEASE}`;
const timeout = timeoutMs();
const [checksumsResponse, signatureResponse] = await Promise.all([
asset(`${release}/checksums.txt`, timeout),
asset(`${release}/checksums.txt.keysig`, timeout),
]);
const [checksums, signature] = await Promise.all([checksumsResponse.text(), signatureResponse.text()]);
if (!signedDigest(checksums, signature)) {
throw new Error("signature check failed for checksums.txt — refusing to install");
}
const expected = expectedDigest(checksums, artifact);
mkdirSync(binDir, { recursive: true });
const part = `${target}.part`;
cleanup(part);
try {
const actual = await download(`${release}/${artifact}`, part, timeout);
if (actual !== expected) throw new Error(`signature check failed for ${artifact} — partial download deleted`);
chmodSync(part, 0o755);
renameSync(part, target);
} catch (error) {
cleanup(part);
throw error;
}
process.stderr.write(`${name} ${os}/${arch} checksum verified\n`);
return target;
}
View on GitHub (pinned to 27d5a3981a)
Solutions
- Do not bypass: this is a deliberate tamper gate — treat the source as untrusted until verified
- Unset CAVE_BINARY_RELEASE_BASE to consume the official release host and retry
- Update the tool or installer to the current version (a newer release may pin the rotated signing key)
- If it persists against the official host, capture checksums.txt plus .keysig and report it upstream as a potential security incident
Example fix
# before CAVE_BINARY_RELEASE_BASE=https://untrusted-mirror/rels … # re-signed assets → failure # after unset CAVE_BINARY_RELEASE_BASE # verify against the official, correctly-signed release
Defensive patterns
Strategy: validation
Validate before calling
// before overriding the release base, confirm the official signature chain applies
if (process.env.CAVE_BINARY_RELEASE_BASE) {
console.warn("custom release base in effect — its signature must match the pinned signing key or install will refuse");
} Try / catch
try { await ensureBinary({ name, envVar }); }
catch (e) {
if (/signature check failed for checksums/.test(String(e?.message))) {
// SECURITY GATE: do not retry or bypass — verify the source, then either
// use the official host (unset CAVE_BINARY_RELEASE_BASE) or report upstream
throw new Error(`possible supply-chain tampering: ${e.message}`);
}
throw e;
} Prevention
- Never disable or work around the checksum-signature gate
- Keep the installer updated so its pinned signing key matches current releases
- Investigate persistent failures against the official host as security incidents
When it happens
Trigger: A tampered, truncated, or regenerated checksums.txt whose signature no longer matches; a sigstore bundle with an unexpected mediaType or digest algorithm; the wrong CAVE_BINARY_RELEASE_BASE serving content signed by a different key; truncated downloads of either file.
Common situations: MITM or compromised mirrors repacking releases; internal mirrors that re-sign or rewrite assets; release pipeline key rotation not yet reflected in the installed client version; network corruption.
Related errors
- signature check failed for checksums.txt — refusing to insta
- signed checksum manifest is malformed
- signature check failed for ${artifact} — partial download de
- cave_mastra_terminal_failure
- cave_harness_incomplete_evidence
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/c648d9ed22326c07.
Report an issue: GitHub.