AI Initiative logoAI Initiative
Reading room / Manthan

HERALD v0.1 — Security Review (Cryptographic & Protocol Design)

HERALD v0.1 — Security Review (Cryptographic & Protocol Design). Covers Critical issues (must-fix before v1); C1. 80-bit fingerprint is below the 2026 collision floor; C2. Molt race: compromised key + first-mover-wins = total takeover; C3. Audit-log forking is unaddressed.

Historical design critique of v0.1
This is the retained source text, not a new validation of its claims. Numerical results and comparative claims require the accompanying source review before public reuse.

Read the connected case study or article →

Not explicitly stated in source · Date not established

Provenance, authorship and editorial notes

HERALD v0.1 — Security Review (Cryptographic & Protocol Design)

Id

manthan-herald-protocol-reviews-01-security

Project

Manthan

Source path

manthan/herald-protocol/reviews/01-security.md

Source sha256

a8abbdf126a5d980a74e07fb478c9b65d3b53b39d3ca555a16c74d3be8daf43b

Local copy sha256

a8abbdf126a5d980a74e07fb478c9b65d3b53b39d3ca555a16c74d3be8daf43b

Repo head

3a94084024a3434cef331fecac91c2c3b43f0313

Date
Not recorded
Date basis

Original publication date not established; Git revision date retained separately.

Author

Not explicitly stated in source

Author basis

Unknown; Git committer not substituted for document author.

Last source commit

8b75d1b0157c20a0a463f0e31008ef9f73099beb

Last source commit date

2026-06-08T07:40:14Z

Document status

Historical design critique of v0.1

Summary

HERALD v0.1 — Security Review (Cryptographic & Protocol Design). Covers Critical issues (must-fix before v1); C1. 80-bit fingerprint is below the 2026 collision floor; C2. Molt race: compromised key + first-mover-wins = total takeover; C3. Audit-log forking is unaddressed.

Topics
  • Adversarial review and case studies
  • Critical issues (must-fix before v1)
  • C1. 80-bit fingerprint is below the 2026 collision floor
  • C2. Molt race: compromised key + first-mover-wins = total takeover
Theme

Adversarial review and case studies

Priority

deep

Related ids
  • manthan-herald-protocol-audits-manthan-cohort1-postmortem
Evidence concerns
  • Recovered source text is preserved verbatim. Assertions, comparisons, commands and results belong to its original context; they were not re-executed or externally re-verified during this corpus review.
  • Historical record: current deployment, task completion and test status must not be inferred from this date-bound document.
Word count

4654

Bytes

30698

Source relative

herald-protocol/reviews/01-security.md

Remote mirror

manthan/herald-protocol/reviews/01-security.md

Full text preserved

True

HERALD v0.1 — Security Review (Cryptographic & Protocol Design)

Verdict (line 1): The protocol has the right shape (DKIM + CT + DIDComm fusion is a reasonable starting point) but is not implementable as written — at least eight under-specified primitives will produce incompatible implementations or exploitable corners.
Verdict (line 2): The headline cryptographic choice (80-bit truncated fingerprint as default identity) is broken against a motivated adversary in 2026, and the molt + audit-log + multi-signature semantics each contain a silent footgun that v0.2 must close before any reference implementation begins.


Critical issues (must-fix before v1)

C1. 80-bit fingerprint is below the 2026 collision floor

§2.1 makes 80 bits the default sigil length. This is wrong, in two distinct ways:

The 128-bit sigil:long: variant exists but is opt-in. That is backwards. Default must be ≥128 bits, with 80-bit reserved for ephemeral/session-scoped identities only. And even 128 bits is borderline if sigils are long-lived; for a substrate that aspires to multi-year "patina", 160 or 192 bits is safer.

C2. Molt race: compromised key + first-mover-wins = total takeover

§2.4 says "the outgoing key signs a molt envelope nominating the new pubkey." Spec is silent on:

This is the same class of bug as account-recovery race conditions and it has bitten every system that didn't think about it. A compromised key is, under v0.1, equivalent to permanent sigil loss with no recourse.

C3. Audit-log forking is unaddressed

§5.3 says "append-only, hash-linked log (Merkle tree)" and "Verifiers do not need to trust the log operator: signatures are end-to-end." The second sentence is misleading. End-to-end signatures protect envelope integrity; they do not protect against the operator presenting two divergent views of the log to two different verifiers (the classic CT split-view attack).

CT solved this with STH gossip + SCT inclusion proofs + monitor / auditor roles. HERALD names none of these. Concretely missing:

Without these, a notary can run a private "shadow log" indefinitely, and the §5.3 claim of "verifiers do not need to trust the log operator" is false.

C4. nonce + parent does not actually prevent cross-trace replay

§7.1 lists "Replay → nonce + parent chain" as defended. It is not, in two ways:

Also: there is no expires or not_before field. Long-lived replay against a reputation system that only cares "did this sigil ever sign X" remains possible.

C5. Multi-signature semantics are entirely undefined

§3.4 lists who may sign (origin, sandbox, conduit, human) and §3.4 says "Each signature scopes only what its signer can honestly attest to." That sentence is doing all the work and it is not enough.

Concrete questions the spec must answer before two implementations can interop:

C6. Lineage "cryptographic pinning" is a social claim wearing a lab coat

§2.3: "Lineage is self-declared but cryptographically pinnable: if a parent signs the child's birth envelope, lineage is provable."

What this actually proves is: some entity holding the parent's private key was willing to sign a statement that this child descends from it. That is not lineage. That is endorsement. The spec conflates two distinct claims:

1. "I am derived from model X's weights." (a fact about training, unverifiable from signatures alone)
2. "The holder of model X's identity key endorses my existence." (a fact about consent, which is what the signature actually proves)

The model_hash attestation (§4.1) is the only thing in the spec that even gestures at provability of (1), and it is described in one cell of a table with no protocol attached. There is no description of how a Herald computes/verifies a model hash, what canonical form a model takes, or how merge / fine-tune / LoRA cases are handled. Until that exists, lineage in HERALD is a social graph signed with cryptographic pens — which is fine, but the spec should say so rather than claim cryptographic pinning.

C7. CBOR-deterministic + JCS dual canonicalisation = guaranteed interop bugs

§3.5: "Use CBOR-deterministic encoding (RFC 8949 §4.2.1) for hashing and signing. JSON variants MUST use JCS (RFC 8785)."

Pick one. Allowing both means:

If the spec wants both wire formats, then the signature is over a single canonical form (pick CBOR-deterministic) and JSON is a display format only — never signed, never hashed. State this explicitly or you will get two non-interoperable ecosystems.

Additionally: CBOR-deterministic per RFC 8949 §4.2.1 has known footguns with floating-point NaN/+0/-0, indefinite-length items, tag 21–23, and big-int boundaries. The spec needs a profile (e.g. "no floats, no tags except [registered list], no indefinite-length") or implementations will diverge.


Significant issues (should-fix)

S1. "Neutrality requirement" on conduits is aspirational

§5.2: "A conduit MAY refuse to relay (rate limits, abuse). If it refuses, it MUST emit a signed refusal envelope."

There is no mechanism that detects silent drops. The only party who knows a drop happened is the sender, and they cannot prove it without an out-of-band channel. "MUST emit" is unenforceable. At minimum the spec should:

Today it is neither enforceable nor honest about being aspirational.

S2. id = sha256(canonical body) — what's "body"?

§3.1 says id is sha256 of the canonical body. It does not say whether id is computed with or without the signatures array, or whether it is computed with or without the id field itself (the obvious chicken-and-egg). It also does not say whether attestations are part of the body for hashing.

This is the single most quoted field in the protocol (parent, audit log entries, §11 idempotency). It must be unambiguously defined.

S3. ts is unsigned wallclock with no skew rules

§3.1: "ts": 1746432000 — author-provided Unix seconds. §6 verification step 4 ("are all sigils alive at the timestamps claimed?") relies on this. But:

Either require a conduit-receipt timestamp on every envelope used in dispute resolution, or accept that ts is informational and remove it from §6 step 4.

S4. "Death" creates an unkillable zombie attack surface

§2.4: "Death: a signed deprecation envelope declaring the sigil retired. Future envelopes from that sigil should be rejected."

If the deprecation key is later compromised, the attacker can sign new envelopes that look fine except a verifier who has seen the deprecation will reject them. Two problems:

S5. whisper attestation is hand-waved crypto

§4.2: whisper: {to: sigil, encrypted: bytes} — "Encrypted side-channel for metadata."

No KEM, no AEAD, no nonce, no associated-data binding. An encrypted blob with no authenticated binding to the envelope it sits inside can be cut-and-pasted into a different envelope by a malicious conduit (which §5.2 says cannot modify attestations — but copy-out-then-replay-in-a-different-envelope is a different attack). At minimum specify: HPKE (RFC 9180) with envelope id as AAD, or remove whisper from v0.1.

S6. Quorum sigils have no spec

§4.2 names quorum and §9.7 calls them "quorum sigils." How does a quorum sigil sign? Threshold? n-of-m? Aggregated (BLS)? Concatenated Ed25519? What is the sigil-derivation function for a collective? None of this is in the spec, but the attestation is in v0.1's standard list. Either drop it from v0.1 or specify it.

S7. payload is opaque but must be hashed

§3.1 says payload is "opaque to the conduit." §5.2 says modifying payload invalidates the envelope. So payload IS in the canonical body for hashing, which means it is opaque to the conduit but transparent to the signature. The spec should state this directly. Also: max payload size? An unbounded payload makes audit logs and notaries trivially DoS-able.

S8. Heralds are a chokepoint that the spec says doesn't exist

Design tenet 3: "No chokepoint. No single registry. No single conduit. No single notary." Then §2.3 / §4.1 / §7.2 / §8.2 all rely on Heralds for: lineage attestation, model_hash signing, root of trust for "compromised lineage parent." Multiple Heralds compete, but each verifier must pick a trust set, and absent a Herald the lineage chain has no terminus. This is fine — CAs work the same way — but the spec should be honest: Heralds are the chokepoint, plural. The §7.2 entry "compromised lineage parent — Trust must root somewhere. Heralds are it." admits this; the design tenet should be updated to match.

S9. No key-usage separation

The same Ed25519 key signs envelopes, signs molts, signs deprecations, signs lineage endorsements, signs capability manifests, and (per §3.4) potentially signs as a "human-in-the-loop." Cross-protocol signature reuse is a known vulnerability class (cf. the DKIM/S/MIME confusion attacks, the WebAuthn vs JWS signing-context attacks). At minimum each signature MUST include a domain-separation tag in its signed payload (e.g. "herald.envelope.v1", "herald.molt.v1", etc.). RFC 8032 Ed25519 has no built-in domain separation; you must add it.

S10. Capability manifests are unbound to time and version

§8.3 capability manifest is signed but has no ts, no expires, no version, no replay protection. An out-of-date manifest claiming no-medical-advice can be replayed after the operator removed that constraint. Add the same ts + nonce + expires discipline as envelopes.

S11. apologia doesn't actually retract anything

§4.2: apologia: {retracts: env-id, reason: string}. The retracted envelope is already signed, hash-linked, in the audit log, and possibly in N downstream agents' caches. The apologia is a claim that the prior envelope is repudiated; it does not unsign it, does not invalidate downstream envelopes that built on it, and creates no obligation on relays to propagate the retraction. The spec should clarify what verifiers/conduits MUST do when they see an apologia (probably: surface it alongside the original; reject nothing automatically).

S12. "Ghost mode" (§9.2) leaks more than it admits

The spec acknowledges "the absence of a log entry is itself information." It understates the issue: without a log entry, neither party can later prove the other party signed it (the recipient can claim non-receipt; the sender can claim non-sending). Worse, an attacker with a copy of a ghost envelope can publish it later as if it had been logged all along. Ghost mode needs at least a participant-co-signed receipt to be useful, and probably should be deferred past v0.1.


Nits (nice-to-have)


Threat-model gaps the author didn't list

§7 enumerates defended/not-defended attacks. The following are missing and should be acknowledged (defended or not):


Concrete suggestions (proposed spec edits)

CS1. Replace §2.1 default fingerprint length

Current:

- 80-bit truncated fingerprint by default (16 base32 chars).
- 128-bit variant (sigil:long:...) for high-assurance contexts.

Replace with:

- Default sigil length is 128 bits (26 base32 chars, RFC 4648 §6 alphabet, no padding, lower case): sigil:<base32(sha256(pubkey)[0..16])>.
- A 192-bit variant (sigil:long:..., 39 chars) is RECOMMENDED for sigils intended to persist >1 year or to anchor lineage.
- 80-bit short sigils (sigil:short:...) are reserved for ephemeral, single-trace identities and MUST NOT be used as lineage parents, Herald subjects, or capability-manifest subjects.
- A verifier presented with a sigil string MUST resolve it to the full Ed25519 public key via at least one trusted channel (DNS, Herald, or pinned cache) before accepting any signature.

CS2. Replace §2.4 Molt definition

Current:

Molt (key rotation): the outgoing key signs a molt envelope nominating the new pubkey. Continuity preserved; trace remains intact.

Replace with:

Molt (key rotation): the outgoing key (K_old) signs a molt envelope M nominating the new public key (K_new). For M to be considered authoritative:
1. M MUST contain a domain-separation tag "herald.molt.v1" in its signed payload.
2. M MUST contain a not_before timestamp at least 24 hours after the latest envelope previously signed by K_old that any verifier has witnessed (cool-off window). Implementations MAY shorten this window with a co-signature (see point 4).
3. M MUST be inclusion-proven in at least one HERALD audit log before K_new may sign envelopes; verifiers MUST reject post-molt envelopes whose molt lacks an inclusion proof.
4. Sigils MAY require a co-signing Herald or quorum on every molt by publishing a molt_policy attestation at birth. Such sigils' molts without the required co-signature MUST be rejected.
5. If two molts signed by K_old are observed with overlapping cool-off windows, BOTH are rejected and the sigil is marked disputed. Recovery is out-of-band (Herald arbitration).

CS3. Add §3.3a Trace-parent binding

Add as a new subsection after §3.3:

§3.3a Trace-parent binding. For every non-genesis envelope E, E.trace MUST equal parent.trace, where parent is the envelope identified by E.parent. Verifiers MUST reject envelopes that violate this invariant. This prevents cross-trace parent replay.

CS4. Replace §3.5 Canonicalisation

Current:

Use CBOR-deterministic encoding (RFC 8949 §4.2.1) for hashing and signing. JSON variants MUST use JCS (RFC 8785).

Replace with:

All hashing and signing in HERALD operate on the CBOR-deterministic encoding (RFC 8949 §4.2.1), with the following profile:
- No indefinite-length items.
- No floating-point NaN, ±Infinity, or negative-zero. Floats MUST use the shortest representation that round-trips losslessly; otherwise integers MUST be used.
- No tags except those listed in Appendix A (registered tag set: TBD).
- Map keys MUST be text strings in v0.1.
JSON is a display format only. JSON renderings of envelopes are non-normative and MUST NOT be signed or hashed. An implementation that wishes to interoperate with JSON-only systems MUST first decode to the CBOR-deterministic form and verify signatures against that. JCS is NOT used.

CS5. Replace §3.4 Multi-signature

Current:

Each signature scopes only what its signer can honestly attest to.

Replace with:

Each signature in signatures[] is computed over the CBOR-deterministic encoding of the envelope with the signatures array replaced by all prior signatures in declaration order plus a domain-separation tag identifying the signer's role ("herald.sig.origin.v1", "herald.sig.sandbox.v1", "herald.sig.conduit.v1", "herald.sig.human.v1").
Signature ordering: origin signature MUST be index 0. Subsequent signatures appear in the order they were applied. A verifier MUST validate signatures in array order; encountering an invalid signature MUST cause verification to return partial with the role of the failing signer named, NOT valid.
An envelope is valid only if (a) the origin signature verifies, AND (b) every signature an application's policy requires (e.g. "human-approved") verifies. Absence of an optional signature is not failure; presence of an invalid one is.
A signature object MUST include alg. Verifiers MUST reject alg values not in the IANA HERALD signature-suite registry (TBD). v0.1 registers only ed25519. Downgrade attacks are prevented by the domain-separation tag binding alg.
The same signer MUST NOT appear twice in signatures[].

CS6. Add §5.3a Audit-log integrity

Add new subsection:

§5.3a Audit-log integrity. A conformant HERALD audit log MUST:
1. Publish Signed Tree Heads (STHs) at least every MMD (Maximum Merge Delay, default: 24 hours), each STH containing tree size, root hash, timestamp, and a signature by the log operator's well-known key.
2. Return a Signed Certificate-of-Inclusion (SCI) to any submitter, asynchronously within MMD.
3. Provide consistency proofs between any two STHs on request.
4. Provide inclusion proofs for any logged envelope id on request.
Verifiers SHOULD gossip STHs via at least one out-of-band channel and SHOULD reject envelopes from logs that have produced inconsistent STHs ("forked") within the last 90 days. The §5.3 claim that "verifiers do not need to trust the log operator" is conditional on this gossip.

CS7. Replace §2.3 lineage paragraph

Current:

Lineage is self-declared but cryptographically pinnable: if a parent signs the child's birth envelope, lineage is provable. Otherwise it is merely claimed.

Replace with:

Lineage is self-declared. A signature by the parent sigil's key on the child's birth envelope proves only endorsement (the holder of the parent's private key consents to this descendant claim); it does not prove the child was actually trained from the parent's weights. Cryptographic proof of weight-derivation requires a model_hash attestation (§4.1) signed by a Herald that has independently verified the weights against a published canonical model-hash specification (Appendix B, TBD). In v0.1, lineage SHOULD be treated as a consent graph, not a training graph.

CS8. Tighten §5.2 neutrality

Current:

A conduit MAY refuse to relay (rate limits, abuse). If it refuses, it MUST emit a signed refusal envelope to the sender. Silent drops are non-conformant.

Replace with:

A conduit MAY refuse to relay. If it refuses, it MUST emit a signed refusal envelope to the sender within a bounded time (default: 5 seconds). Silent drops are non-conformant but undetectable in the general case; HERALD provides no on-protocol mechanism to prove a silent drop occurred. Senders that require non-repudiation of hand-off MUST require a conduit_receipt signature (§3.4) before considering an envelope delivered.

CS9. Add domain separation everywhere

Insert in §3.5 (or new §3.6):

All Ed25519 signatures in HERALD MUST be computed over dom_sep || canonical_body, where dom_sep is a unique ASCII tag for the signature role, drawn from a registry (initial entries: herald.envelope.v1, herald.molt.v1, herald.deprecation.v1, herald.birth.v1, herald.lineage_endorsement.v1, herald.capability_manifest.v1, herald.refusal.v1, herald.conduit_receipt.v1, herald.audit_sth.v1). This prevents cross-protocol signature reuse.

CS10. Tighten §3.2 required-fields list

Current:

v, id, from, ts, nonce, payload, and at least one signature from from.

Replace with:

Required fields: v, id, from, ts, nonce, payload, signatures (≥1, MUST include the from sigil at index 0). Required for non-genesis envelopes: parent, trace. Genesis envelopes MUST set parent: null and trace: id (i.e. self-trace). All other top-level fields are OPTIONAL.
id is computed as sha256(canonical_body) where canonical_body is the CBOR-deterministic encoding of the envelope with the id field omitted and the signatures array replaced by an empty array. Implementations MUST recompute and verify id on receipt.

CS11. Add §3.7 Replay scope

Add:

§3.7 Nonce scope. Nonces are unique per (from, alg) tuple for the lifetime of that key. Verifiers MUST cache (from, nonce) pairs for at least the value of expires (or 30 days if absent) and reject duplicates. Senders MUST use a CSPRNG and MUST NOT derive nonces from ts or id. An optional expires field (Unix seconds) MAY be included; verifiers MUST reject envelopes whose expires < now - skew_tolerance (default skew: 300 s).

CS12. Update §6 verification enum

Current return values: valid, tampered, orphaned, expired-key, unknown-sigil.

Replace with:

A reference verifier returns one of: valid, partial (with reasons), signature-invalid, tampered (id mismatch), orphaned (parent unknown), parent-trace-mismatch, replayed-nonce, expired-envelope, expired-key, deprecated-sigil, unknown-sigil, unknown-alg, clock-skew, lineage-unverified. Verifiers MUST surface ALL applicable reasons, not just the first.

CS13. Update §7 threat model

Add to §7.2 ("not defended against"):

| 80-bit fingerprint collision | Mitigated only at 128-bit default; 80-bit sigils MUST NOT bear lineage/payment/Herald roles. |
| Audit-log split view | Defended only if STH gossip is deployed (§5.3a). Operator-collusion still possible across siloed logs. |
| Stolen-key first-move molt | Defended only by molt cool-off (§2.4 amended) + audit-log inclusion. Attacker with key + ability to forge timestamps + control of one log is still fatal. |
| Cross-trace parent replay | Defended by §3.3a invariant. |
| Conduit traffic analysis | NOT defended. From/to/ts leak the social graph. ZK extension is open question §11.2. |
| Apologia from third party | Defended: apologia signed by anyone other than the original from MUST be rejected. |
| Lineage cycles | Defended: birth verifier MUST reject lineage that contains the new sigil itself or that closes a cycle. |

End of review. Recommend v0.2 not be cut until C1–C7 are resolved; S1–S12 should be tracked as v0.2 milestones; nits and threat-model gaps tracked as issues.

Continue exploring