verify_signature checks the signature against the key carried inside the receipt:
vk = VerifyKey.from_base64(receipt.signature.public_key)
That is the right primitive, and expected_public_key exists to pin the signer, and the README is honest that key trust is the caller's problem. The gap is in what an unpinned run reports.
Today, verify_receipt(receipt) with no expected_public_key on a receipt that an attacker rewrote and re-signed with their own key returns valid: True, with every check passed and nothing in skipped. The signature genuinely is valid. It just says nothing about provenance, which is the entire point of the receipt.
The signer_pin check is documented as optional in the README table, so someone reading the output at a glance has no way to tell a proven receipt from an unproven one.
Proposal
When no signer is pinned, record it. Either add "signer_pin" to skipped with a detail line saying the signature was not tied to any known signer, or, stronger, make an unpinned verify report a distinct state rather than plain valid. The CLI should say the same thing in words, and answerproof verify without --expect-key should print a one-line warning.
Acceptance
- An unpinned verify makes it visible in both the JSON verdict and the CLI output that no signer was pinned
- A pinned verify is unchanged
- The README table distinguishes the two outcomes
- A test covers the attacker case: tamper with the payload, re-sign with a fresh key, and assert the verdict is not presented as a clean pass
verify_signaturechecks the signature against the key carried inside the receipt:That is the right primitive, and
expected_public_keyexists to pin the signer, and the README is honest that key trust is the caller's problem. The gap is in what an unpinned run reports.Today,
verify_receipt(receipt)with noexpected_public_keyon a receipt that an attacker rewrote and re-signed with their own key returnsvalid: True, with every check passed and nothing inskipped. The signature genuinely is valid. It just says nothing about provenance, which is the entire point of the receipt.The
signer_pincheck is documented as optional in the README table, so someone reading the output at a glance has no way to tell a proven receipt from an unproven one.Proposal
When no signer is pinned, record it. Either add
"signer_pin"toskippedwith a detail line saying the signature was not tied to any known signer, or, stronger, make an unpinned verify report a distinct state rather than plainvalid. The CLI should say the same thing in words, andanswerproof verifywithout--expect-keyshould print a one-line warning.Acceptance