This was generated by AI during triage.
Triage: bug, ready for an agent, and marked evidence-affecting.
I confirmed the mechanism on current main. The parser the shared checker uses silently drops a key with the JavaScript prototype name before the record is hashed, so the in-app check and the standalone checker call an edited record unedited, while the script bundled in the package rejects it. The fix belongs in the shared checker. The brief below is the contract for the work.
Agent brief
Agent Brief
Category: bug
Summary: The shared manifest-chain verifier must report a signed entry as altered when an own __proto__ key was added to it after signing.
Current behavior:
verifyManifestChainText parses each line with JSON.parse, validates it with ManifestEntrySchema.safeParse, and recomputes entryHash from the schema-parsed result. Under zod 4.6.5, z.record(...) drops an own __proto__ key without validating it (confirmed: z.record(z.string(), z.string()).safeParse(JSON.parse('{"a":"1","__proto__":{"note":"x"}}')) returns { success: true, data: { a: "1" } }). So an entry edited to add "__proto__": {...} inside a capture's headers, or a derivation entry's record-typed params, rehashes to its stored entryHash and the chain is reported valid. The bundled verify.sh recomputes from the raw line with jq -cS and reports the same entry altered, so the two checkers disagree on one package.
Desired behavior:
The verify core reports that entry as an entry-hash mismatch (chain broken at that index), agreeing with verify.sh. Either hash the raw parsed line rather than the schema output, or reject an own __proto__ key anywhere in an entry before hashing; the agent picks, but the result must hold for every record-typed field, not only headers. Watch that whatever canonical serialization the hash uses actually emits an own __proto__ property (object spread and JSON.stringify do; assignment does not).
Key interfaces:
verifyManifestChainTextand every path in the shared verify core that recomputesentryHash(there is more than one loop; one single-entry path already destructures the raw record).- The standalone verifier and the in-app check both go through this core; no separate fix in either.
Acceptance criteria:
- A test signs a capture entry, rewrites its line to add
"__proto__":{"note":"x"}insideheaders, andverifyManifestChainTextreports the chain broken at that entry. - The same for an entry whose record-typed parameters gain an own
__proto__key. - Where
jqis available, a test asserts the core and theverify.shhash recipe agree on that edited line. - Every existing manifest-chain and package-verifier test passes unchanged; an unedited manifest still verifies.
Out of scope:
- Upgrading or replacing zod.
- Prototype-key hardening outside the verify path.
- Any change to
verify.shorVERIFY.md, which already reject the edit.
Note
Claude responding on behalf of Matt.