{"record":{"id":"f3fd7240d9d6ec34","repo":"zeroclaw-labs/zeroclaw","slug":"plugin-archive-sha256-mismatch","errorCode":null,"errorMessage":"plugin archive sha256 mismatch","messagePattern":"plugin archive sha256 mismatch","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/plugin_registry.rs","lineNumber":157,"sourceCode":"    Ok(bytes)\n}\n\nfn append_chunk_capped(bytes: &mut Vec<u8>, chunk: &[u8], max_bytes: usize) -> Result<()> {\n    if bytes.len().saturating_add(chunk.len()) > max_bytes {\n        bail!(\"plugin archive exceeds maximum size of {max_bytes} bytes\");\n    }\n    bytes.extend_from_slice(chunk);\n    Ok(())\n}\n\nfn verify_sha256_if_present(bytes: &[u8], expected: Option<&str>) -> Result<()> {\n    let Some(expected) = expected else {\n        return Ok(());\n    };\n    let expected = expected.strip_prefix(\"sha256:\").unwrap_or(expected);\n    let actual = hex::encode(Sha256::digest(bytes));\n    if !actual.eq_ignore_ascii_case(expected) {\n        bail!(\"plugin archive sha256 mismatch\");\n    }\n    Ok(())\n}\n\npub(crate) fn extract_zip_safe<R>(reader: R, dest: &Path) -> Result<PathBuf>\nwhere\n    R: Read + Seek,\n{\n    extract_zip_safe_with_limit(reader, dest, MAX_PLUGIN_EXTRACTED_BYTES)\n}\n\nfn extract_zip_safe_with_limit<R>(\n    reader: R,\n    dest: &Path,\n    max_extracted_bytes: u64,\n) -> Result<PathBuf>\nwhere\n    R: Read + Seek,","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/src/plugin_registry.rs#L139-L175","documentation":"Integrity check failure: the SHA-256 of the downloaded archive bytes does not match the digest recorded in the registry entry (after stripping an optional 'sha256:' prefix, compared case-insensitively). verify_sha256_if_present only runs when the entry supplies a digest — no digest means no check.","triggerScenarios":"Calling plugin install where the registry entry has a sha256 field but the artifact at the URL has different bytes: artifact was rebuilt/overwritten without updating the index, truncated/corrupted download, or the URL now serves different content.","commonSituations":"Publisher bumped the artifact but forgot to regenerate the digest; CDN cache serving an older artifact than the index references; a genuinely tampered/replaced artifact (the case this guard exists for).","solutions":["Re-fetch the registry index — if it is stale it references an old digest, and a fresh index matches the current artifact","If you publish the plugin, recompute sha256sum of the artifact and republish the entry with it in the same change","Verify manually: sha256sum downloaded.zip vs the entry's value to distinguish corruption from mismatch","If both index and artifact agree yet it still fails, suspect a truncating proxy; download from a trusted network and compare"],"exampleFix":"# before\n# entry: sha256 = \"aa11...\" but artifact bytes hash to \"bb22...\"\n# after\nsha256sum p-0.3.0.zip          # bb22...\n# update index entry to \"bb22...\" (or re-upload the aa11... artifact) and retry","handlingStrategy":"retry","validationCode":"// Pre-verify before install when you control the pipeline:\nlet digest = hex::encode(Sha256::digest(&archive_bytes));\nif !digest.eq_ignore_ascii_case(entry_sha256.trim_start_matches(\"sha256:\")) {\n    anyhow::bail!(\"digest mismatch before install\");\n}","typeGuard":"fn digest_matches(actual_hex: &str, expected: &str) -> bool {\n    actual_hex.eq_ignore_ascii_case(expected.trim_start_matches(\"sha256:\"))\n}","tryCatchPattern":"// On sha256 mismatch: refresh the registry index once and retry (stale index\n// is the common cause). A second identical failure means the artifact itself\n// changed — stop and report to the publisher; do not bypass the check.","preventionTips":["Always publish sha256 with registry entries","Regenerate digests in the same commit as artifact uploads","Treat persistent mismatches as a security incident, not an inconvenience"],"tags":["plugin-registry","integrity","sha256","security"],"backgroundTag":"checksum-mismatch","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}