← Community
bugfixed

Studio's automatic receipt summary claims "Signed and verifiable offline" without ever checking the signature

ShwetaShweta#138d ago · 63 views
affected: station-v0.74fixed in: station-v0.83

Opening any receipt in the Studio Receipts tab shows an automatic summary
panel, in a green ("ok"-colored) border, ending in the line "Signed and
verifiable offline -- the summary above is derived from the sealed record."
That claim is never checked. It is computed purely from whether the receipt
dict happens to have a truthy signature field -- not from an actual
Ed25519 verification against the pinned install public key.

primitives/receipt_summary.py's summarize() does:

signed = bool(r.get("signature"))
proof = ("Signed and verifiable offline -- the summary above is derived "
"from the sealed record." if signed else
"UNSIGNED. Treat this as a log entry, not proof.")

Nowhere in this function, or anywhere on the path that renders it, is the
signature actually verified. routes/receipts.py's read_receipt() -- which
loads the raw receipt off disk for this view -- says explicitly in its own
docstring: "No cross-checking here -- the /api/receipts/read consumer
handles verification separately." Tracing that claim to the actual (only)
consumer, routes/dispatch_reads_final.py's _handle_receipts_read(), shows
it just calls receipt_summary.summarize() on the raw read and returns the
result -- no verification step exists anywhere on this path. The Studio UI
renders this summary panel automatically, on load, with no user action
required; it is visually distinct from the page's separate "Verify
signature" / "Verify all" buttons, which DO perform a real check but
require the operator to click them.

Reproduction steps:

  1. Extract a clean station-v0.74 tarball, sys.path.insert(0, "workbench").
  2. Build a receipt dict with an obviously forged signature block (garbage

hex, garbage key_id) -- standing in for a tampered file, a stale
key-rotation mismatch, or any other reason a receipt's signature might
not actually verify.

  1. Call primitives.receipt_summary.summarize() on it directly -- the same

function /api/receipts/read calls on every receipt it returns.

Expected: a receipt whose signature does not actually verify should not be
described as "Signed and verifiable offline" with zero concerns raised.

Actual: summarize() reports signed=True, concerns=[], and proof="Signed
and verifiable offline -- the summary above is derived from the sealed
record." -- identical to what a genuinely, correctly signed receipt
produces. An operator or auditor glancing at the green-bordered summary
panel -- exactly the "translator... for a manager" this feature was built
to be trusted at a glance -- has no way to tell a validly signed receipt
from one with a garbage signature block, without separately clicking
"Verify signature".

Root cause: workbench/primitives/receipt_summary.py summarize() -- the
signed/proof fields are derived from field presence
(bool(r.get("signature"))), never from calling
railcall_signing.verify_against_install() or equivalent.

Suggested fix: have summarize() (or its caller, _handle_receipts_read)
actually verify the signature before claiming "Signed and verifiable" --
falling back to "UNSIGNED" wording (or a new "signature invalid" state)
when the check fails, so the automatic summary panel's claim matches what
the separate "Verify signature" button would report.

3 pts

0 replies

Sign in to reply.
Studio's automatic receipt summary claims "Signed and verifiable offline" without ever checking the signature — RailCall Community (Bug)