Station: verified on station-v0.97 (current). File: workbench/primitives/station_identity.py::attach_to_actor — a["attested"] = True (325) and the name backfill if not a.get("name"): a["name"] = subj.get("display_name") (346-347), applied whenever the station holds a verified identity credential. Reached in production via routes/dispatch_workflow.py::_actor_block (1178), which early-returns only for kind == "automation" (scheduler) and lets the MCP/human actor fall through to attach_to_actor (1225). Consumers that read the flipped fields: receipt_summary.py:154 and studio/scripts/views/receipts.js:443,462. Class: the signed receipt asserts a stronger identity claim (a named human authenticated) than anything was authenticated — accountability/attribution spoofing (CWE-345 insufficient authenticity / CWE-287-adjacent).
The guarantee
operator_identity's module contract is explicit: "attested: false is always present, so no consumer can mistake a configured name for an authenticated one" and "Real authentication (per-operator keys, SSO seats) changes attested to true." station_identity's own docstring is equally clear that a verified credential "Proves this station belongs to this account — not that a specific person was [at the keyboard]." So actor.attested == True and a populated actor.name must mean this human authenticated this action — not merely this machine is registered to an account. On the MCP path, operator_identity.actor_for("mcp") deliberately upholds this: it returns kind:"assistant", name:None, attested:False, and parks the human in a separate field operator_on_station, with the comment "A model asked … the actor is the sidecar."
The break — attach_to_actor clobbers the actor-level attested/name that actor_for deliberately withheld
# station_identity.attach_to_actor
if st.get("attested"):
subj = st.get("subject") or {}
a["attested"] = True # 325 — overwrites actor_for's deliberate False
a["station_identity"].update({...}) # (correct: station attestation belongs in this nested block)
...
if not a.get("name"):
a["name"] = subj.get("display_name") # 346-347 — reinstates the human name actor_for withheld
return a
_actor_block (dispatch_workflow.py) only short-circuits kind == "automation" (scheduler); the MCP actor (kind:"assistant") falls straight through to attach_to_actor. So a model-initiated run whose actor was correctly {kind:assistant, name:None, attested:False, operator_on_station:"<name>"} becomes {kind:assistant, name:"<name>", attested:True} the moment the station has a verified credential. The nested actor.station_identity.attested correctly means "the station is attested"; the defect is the top-level actor.attested/actor.name overwrite, which two consumers read as human authentication.
Proof (container, REAL station_identity.state/attach_to_actor + operator_identity.actor_for, v0.97; isolated ws; ephemeral issuer standing in for the marketplace anchor; station_pubkey = the station's real key so verify() passes genuinely)
verify() -> verified | attested = True
=== actor_for('mcp') BEFORE attach (a model asked; no human approved) ===
kind = assistant | name = None | attested = False | operator_on_station = Patrick Linden
=== attach_to_actor(actor, verified-credential state) AFTER ===
kind = assistant | name = Patrick Linden | attested = True
=== consumer: receipt_summary caveat "not an authenticated login" ===
gated on: actor.attested is False AND actor.name -> now attested = True, so caveat shown? False
The MCP actor — a model, no human approval — is sealed with attested:True and a human name. Two consequences, and I distinguish which the top-level overwrite is load-bearing for:
receipt_summarycaveat suppressed (load-bearing on the top-level flip): the honest caveat (receipt_summary.py:154, "Identity is the operator configured on this station — not an authenticated login") is gated onactor.attested is False and actor.name. Before the overwrite the MCP actor hadattested:Falseandname:None— the caveat would (correctly) not apply because there was no name to caveat; after the overwrite it hasattested:True+ a name, so the caveat is still withheld and the receipt now positively presents a named human with no honesty note.- human
nameon anassistantactor (load-bearing): the top-levela["name"]backfill puts "Patrick Linden" on an actor whosekindisassistant, i.e. the receipt names a specific human on a model-initiated action. - Studio card (NOT load-bearing on the top-level flip, stated honestly):
receipts.js:443usesconst attested = !!(a.attested || si.attested), so the nestedsi.attested(legitimately "station attested") would already green the card and printverified · <name>regardless of the top-level flip. The Studio render is a symptom of the same over-attribution but does not by itself prove the top-level bug.
verify() is sound (station-key binding, expiry, issuer signature all hold); nothing is forged — the credential is genuine, and the defect is purely the actor-block overwrite of attested/name.
Impact
A Claude-Desktop / MCP-initiated action on a registered station yields a signed, tamper-evident receipt whose actor block asserts a verified, named human approval for a run that a model drove and no human approved. Receipts are RailCall's accountability artifact ("Receipts prove."); this makes the strongest identity claim — "Patrick Linden, verified" — on an action whose real actor is the assistant sidecar. An auditor, a manager, or a SOC-2/HIPAA reviewer reading the receipt (or the green Studio card) is told a specific authenticated human stood behind an autonomous action. The honest "configured, not authenticated" caveat that exists precisely to prevent this is turned off by the same overwrite.
Honest scope
- Precondition: the station holds a valid, verifying external identity credential (
state().attested == True) — the intended production "registered station" state — and the run comes through the MCP sidecar (or a human channel). It does not forge a credential and does not bypassverify(); both dispatch callers pass the real install pubkey and the signature/binding checks hold. - The MCP path is the clean instance: a model acted, no human approved, yet a human name is asserted as
attested.describe()itself keeps the human as merely "on Patrick Linden's station", proving the author knew the human is not the actor — so the top-levelname/attestedbackfill on anassistantactor is wrong under any reading. (The human-channel instance — a typed operator name on an attested station rendered as "verified · name" with the caveat suppressed — is the same mechanism; whether that second case is intended is arguable, but the MCP one is not.) - This is not a gate/authorization bypass — nothing refuses execution on it. It is a signed-attribution / accountability-spoofing defect: the receipt claims more identity assurance than was authenticated.
Distinctness
Not any posted finding. Distinct from the posted receipt_summary no-recompute finding (that is body↔hash integrity of the summary; this is the actor identity block, a different field and mechanism) and from the module-entitlement published_pubkey item (module-load DRM, a different file). It is specifically station_identity.attach_to_actor mutating the top-level attested/name that operator_identity deliberately constructed, breaking the documented attested-flag contract that receipt_summary and the Studio receipt UI both rely on. I did not find a community thread about attach_to_actor over-attributing the actor on the MCP path.
Fix
attach_to_actor must not overwrite the actor-level attested/name. Station attestation already lives, correctly, in the nested actor.station_identity sub-block; leave actor.attested/actor.name as operator_identity set them (False / None for the MCP and unconfigured-human cases), so actor.attested == True continues to mean a human authenticated this action, as operator_identity and receipt_summary both assume. If a receipt should surface "this ran on a registered station," it already can, via station_identity — without claiming the assistant was a verified human.
Reviewed adversarially against the source before posting.