Skip to content

fix(#59/JG-RT-026): pin Action Manifest verifier key out-of-band#54

Merged
tattoosonmyskin merged 1 commit into
mainfrom
fix-rt026-manifest-pinned-key
Jun 30, 2026
Merged

fix(#59/JG-RT-026): pin Action Manifest verifier key out-of-band#54
tattoosonmyskin merged 1 commit into
mainfrom
fix-rt026-manifest-pinned-key

Conversation

@tattoosonmyskin

Copy link
Copy Markdown
Contributor

Internal red-team (#59) of the freshly-merged Action Manifest (#62) found a key-trust gap.

Finding (JG-RT-026, MED)

--verify-manifests read the trusted Ed25519 public key from <audit-log>.manifests.pub — a file in the same directory as the log it verifies. An attacker who can rewrite the log can also rewrite that pubkey: regenerate self-consistent manifests signed with their own key, publish that key, and the verifier reports OK. That silently defeats the non-repudiation the manifests exist to provide. (The original forgery_with_different_key… test only passed because it manually restored the genuine pubkey, masking the gap.)

Fix

  • verify_manifests() takes an optional pinned key; CLI adds --manifest-pubkey <hex> (out-of-band).
  • Pinned → in-dir pubkey ignored, authenticity checked against the pinned key (the only mode resisting a malicious log-holder).
  • Unpinned → convenience fallback to the in-dir key (accidental-corruption detection only); result flagged pubkey_pinned=false and reported as "self-consistency only," never mistakable for authenticity.

Validation

  • New regression test swapped_pubkey_forgery_defeated_only_by_pinned_key (8 manifest tests total); full ts_cli suite green; fmt + clippy clean.
  • End-to-end: unpinned → OK "key NOT pinned"; pinned-genuine → OK "authentic"; pinned-wrong → authenticity FAIL exit 70.
  • Docs: THREAT_MODEL §12.1 (key-distribution rule), RED_TEAM_FINDINGS.md JG-RT-026, CHANGELOG.

🤖 Generated with Claude Code

Internal red-team of the new Action Manifest (#62) found the verifier
trusted `<log>.manifests.pub` — a key file beside the very log it checks.
An attacker who can rewrite the audit log can also rewrite that pubkey and
re-sign with their own key, yielding a self-consistent forgery that reported
OK and silently defeated non-repudiation.

Fix: `verify_manifests()` takes an optional pinned key; CLI adds
`--manifest-pubkey <hex>` (supplied out-of-band). When pinned, the in-dir
pubkey is ignored and authenticity is checked against the pinned key — the
only mode resisting a malicious log-holder. When omitted, the verifier falls
back to the in-dir key for convenience (accidental-corruption detection only)
and the result is flagged `pubkey_pinned=false` / "self-consistency only",
so an unpinned pass can never be read as proven authenticity.

Regression: swapped_pubkey_forgery_defeated_only_by_pinned_key. Docs:
THREAT_MODEL §12.1 (key-distribution rule), RED_TEAM_FINDINGS.md JG-RT-026,
CHANGELOG. End-to-end verified (unpinned/pinned/wrong-key).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tattoosonmyskin tattoosonmyskin merged commit 0a9cf0a into main Jun 30, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants