You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RT-002 follow-up: signature-carrying wire formats for the remaining untrusted KEL transports
RT-002 (the systemic "verify path replays a KEL by structure only, never checks event
signatures") is closed for every transport that can carry CESR signature attachments:
CI --identity-bundle — IdentityBundle.kel_attachments + validate_signed_kel
at load_bundle_trust (crates/auths-cli/src/commands/verify_commit.rs), with two
negative e2e tests (stripped / forged signatures fail closed).
WASM validateKelJson — now takes a parallel attachments_json and routes
through validate_signed_kel; an absent/short attachment list fails closed.
Storage foundation — every RegistryBackend persists + exposes attachments
(lossy trait defaults removed; Git/Fake/Postgres/Arc all implement append_signed_event/get_attachment).
Structural prevention — xtask check-verify-path-completeness (CI-wired) bans
structural validate_kel*/replay_kel on the verifier + CLI-verify surfaces unless
the site carries an rt-002-allow: justification.
The sites that still call structural validate_kel* are grandfathered by rt-002-allow: annotations because their KEL is authenticated at the ingestion
boundary (bundle → validate_signed_kel; local registry = trusted self-owned store).
The residuals below are the boundaries that cannot yet authenticate because their
wire format carries no signatures. Each annotation points here.
Residual 1 — --oobi (HTTP) distribution format carries no signatures
HttpOobiResolver::fetch_kel (crates/auths-infra-http/src/oobi_resolver.rs) parses .well-known/keri/oobi/<aid>/keri.cesr as bare-event JSON (Vec<Event>, no
attachments). Prefix-binding is enforced, so a forged inception can't smuggle a
foreign prefix — but forged appendedixn/rot events pass (RT-002). Work: make the OOBI body a real CESR stream (events + attachments), then have resolve_signer_kel run validate_signed_kel (root standalone; delegated device with
the root lookup — the org-bundle pattern). This is a distribution-format change
(producer + client), analogous to the widget (auths-verify-widget#4). See also #231.
RemoteKelSource::fetch_kel (crates/auths-storage/src/git/remote.rs) reads into a
temp GitRegistryBackend that does hold attachments, but KelResolverChain::reconcile / resolve_signer_kel return bare Vec<Event> and drop
them. For a stranger (nothing local) the remote KEL is taken wholesale and replayed
structurally. Work: thread per-event attachments through reconcile/choose_newer_no_rollback
and authenticate at verify_one_commit (root standalone; delegated device with the
root lookup). Feasible entirely in-repo (the data is already on the git registry). See
also #212.
validateKelJson is now authenticated, but verifyDeviceLink
(crates/auths-verifier/src/wasm.rs → verify.rs), verify_credential
(credential.rs), and verify_presentation (presentation.rs) still take bare Vec<Event> KELs across the untrusted WASM boundary. The attestation/credential/
presentation signature is bound to the replayed key-state, so a forged appended
event chain can bind an attacker key. Work: give these entrypoints signature-carrying inputs (attachments alongside the
KEL) and route through validate_signed_kel, mirroring validateKelJson.
Acceptance
For each residual: the transport supplies CESR attachments, the verify path runs validate_signed_kel, and the corresponding rt-002-allow: annotation is removed
(the check-verify-path-completeness lint then re-requires the authenticated call). Add
a forged-signature negative test per transport.
RT-002 follow-up: signature-carrying wire formats for the remaining untrusted KEL transports
RT-002 (the systemic "verify path replays a KEL by structure only, never checks event
signatures") is closed for every transport that can carry CESR signature attachments:
--identity-bundle—IdentityBundle.kel_attachments+validate_signed_kelat
load_bundle_trust(crates/auths-cli/src/commands/verify_commit.rs), with twonegative e2e tests (stripped / forged signatures fail closed).
verify_org_bundlenow runsauthenticate_bundled_kel→
validate_signed_kelover the org KEL and each delegated member KEL(
crates/auths-sdk/src/domains/org/offline_verify.rs); closes fn-154.6 follow-up: full cryptographic KEL-replay of bundled signatures in offline verify (validate_kel) #233, with aforged-signature negative test in
org_delegation.rs.validateKelJson— now takes a parallelattachments_jsonand routesthrough
validate_signed_kel; an absent/short attachment list fails closed.RegistryBackendpersists + exposes attachments(lossy trait defaults removed; Git/Fake/Postgres/Arc all implement
append_signed_event/get_attachment).xtask check-verify-path-completeness(CI-wired) bansstructural
validate_kel*/replay_kelon the verifier + CLI-verify surfaces unlessthe site carries an
rt-002-allow:justification.The sites that still call structural
validate_kel*are grandfathered byrt-002-allow:annotations because their KEL is authenticated at the ingestionboundary (bundle →
validate_signed_kel; local registry = trusted self-owned store).The residuals below are the boundaries that cannot yet authenticate because their
wire format carries no signatures. Each annotation points here.
Residual 1 —
--oobi(HTTP) distribution format carries no signaturesHttpOobiResolver::fetch_kel(crates/auths-infra-http/src/oobi_resolver.rs) parses.well-known/keri/oobi/<aid>/keri.cesras bare-event JSON (Vec<Event>, noattachments). Prefix-binding is enforced, so a forged inception can't smuggle a
foreign prefix — but forged appended
ixn/rotevents pass (RT-002).Work: make the OOBI body a real CESR stream (events + attachments), then have
resolve_signer_kelrunvalidate_signed_kel(root standalone; delegated device withthe root lookup — the org-bundle pattern). This is a distribution-format change
(producer + client), analogous to the widget (auths-verify-widget#4). See also #231.
Residual 2 —
--remotestranger git fetch discards attachmentsRemoteKelSource::fetch_kel(crates/auths-storage/src/git/remote.rs) reads into atemp
GitRegistryBackendthat does hold attachments, butKelResolverChain::reconcile/resolve_signer_kelreturn bareVec<Event>and dropthem. For a stranger (nothing local) the remote KEL is taken wholesale and replayed
structurally.
Work: thread per-event attachments through
reconcile/choose_newer_no_rollbackand authenticate at
verify_one_commit(root standalone; delegated device with theroot lookup). Feasible entirely in-repo (the data is already on the git registry). See
also #212.
Residual 3 — WASM
verifyDeviceLink+verify_credential/verify_presentationvalidateKelJsonis now authenticated, butverifyDeviceLink(
crates/auths-verifier/src/wasm.rs→verify.rs),verify_credential(
credential.rs), andverify_presentation(presentation.rs) still take bareVec<Event>KELs across the untrusted WASM boundary. The attestation/credential/presentation signature is bound to the replayed key-state, so a forged appended
event chain can bind an attacker key.
Work: give these entrypoints signature-carrying inputs (attachments alongside the
KEL) and route through
validate_signed_kel, mirroringvalidateKelJson.Acceptance
For each residual: the transport supplies CESR attachments, the verify path runs
validate_signed_kel, and the correspondingrt-002-allow:annotation is removed(the
check-verify-path-completenesslint then re-requires the authenticated call). Adda forged-signature negative test per transport.
Cross-refs
Closes-the-loop on #233 (org bundle, done). Related: #212 (native KEL distribution),
#231 (OOBI discovery), auths-verify-widget#4 (external widget signature-carrying input).
Source audit:
docs/prompts/red_team_2026_06_10.md(RT-002).