Skip to content

Bind the Agent Manifest identity to the runtime session subject and TRACE Trust Record #302

@carloshvp

Description

@carloshvp

Context

The industrial-embodied-ai example (agentrust-io/examples#16, refined in #18
and #27) documents this under "Evidence boundaries": the Agent Manifest declares
a signed agent identity and the approved prompt, policy and tool hashes, but the
current preview does not bind that identity to the runtime session. The README
states it plainly: the current preview does not cryptographically bind that
manifest identity to the runtime session.

This is the identity member of the same binding family as #301 (independent
controller evidence) and #126 (tool transcript). #301 binds what the controller
did. #126 binds what tools were called. This issue binds who acted.

The gap

The committed Trust Record makes it concrete:

  • trace.subject is spiffe://cmcp.gateway/session/<uuid>, described in
    trace-claim.schema.json as "SPIFFE URI identifying the gateway session".
  • The Agent Manifest agent_id is
    spiffe://factory.example/agent/material-movement/dev, signed together with
    the prompt, policy and tool hashes.

Nothing links the two. cMCP loads the policy bundle and catalog by hash, so an
offline check can confirm the loaded hashes match the manifest's bound hashes.
But cMCP never ingests the manifest, never checks that the identity acting in the
session is the manifest's agent_id, and the Trust Record carries no agent
identity at all, only the session. Verification therefore proves that some
session ran an approved policy and catalog. It does not prove that the agent the
operator reviewed is the agent that acted.

Why this matters for embodied agents

Embodied agents restart, get redeployed, and get replaced. Identity persistence,
proof that the agent that acted is exactly the one that was reviewed, down to its
prompt, policy and tools, is the property that survives those restarts. Without
the binding, an operator can run a different agent (a different system prompt, a
different planner, a different identity) under the same approved policy and
catalog, and the evidence chain will not register the substitution. Permission
and policy hashes are pinned; the actor is not. For a system that moves
machinery, who actually drove this session is not a detail.

Both identities are already SPIFFE URIs, so the binding has a natural spine, and
cMCP already issues SVIDs conditioned on TEE attestation (#96).

Proposed direction

  • Option A, bind at the gateway. At session create, cMCP ingests the signed
    Agent Manifest, verifies the issuer signature against a configured trust
    anchor, checks that the session's authenticated subject (the agent SVID from
    [tee] SPIFFE/SPIRE integration — SVID issuance conditioned on TEE attestation #96) matches manifest.agent_id, and checks that the loaded policy bundle and
    catalog hashes equal the manifest's bound hashes. The Trust Record then carries
    the manifest_id and the bound agent_id alongside the session subject, and
    the verifier asserts the binding. Strongest option, and it reuses the SPIFFE
    path already in place.
  • Option B, bind at verification only. Keep manifest ingestion out of the
    gateway and have the verifier cross-check the offline manifest against the
    Trust Record: session subject consistent with manifest.agent_id, hashes in
    agreement. Lighter, but it only detects a mismatch after the fact and cannot
    refuse a mismatched run at the boundary.
  • Option C, status quo, documented as permanent. Rejected: identity persistence
    is a core property of the trust model, and leaving it undefined invites readers
    to treat a signed manifest as proof of who acted, which it is not today.

Recommendation: Option A as the binding spine, with the Option B verifier check
kept as defense in depth so offline evidence is self-checking.

Scope for a first iteration

  • Manifest ingestion at session create, with issuer signature verification
    against a configured trust anchor.
  • Subject-to-agent_id binding check (SVID equals manifest.agent_id), plus
    policy bundle and catalog hash agreement with the manifest, default deny on
    mismatch.
  • Carry manifest_id and the bound agent_id into the Trust Record, and have
    cmcp-verify assert the binding.
  • Conformance tests: a matching manifest binds and verifies; a mismatched
    agent_id, a tampered manifest signature, and a policy or catalog hash drift
    each fail closed.
  • Update LIMITATIONS.md and the session and trace-claim spec to state exactly
    what the binding does and does not prove.
  • Update the industrial-embodied-ai example to show the bound case. This needs
    the committed signed evidence regenerated from a live run, the same capture
    step flagged in examples#27.
  • Coordinate the canonical manifest shape and signed_fields with the
    agent-manifest SDK (agentrust-io/agent-manifest).

Non-goals

I am happy to own this end to end (spec text, gateway change, conformance tests,
and the example update), in a personal capacity.

Metadata

Metadata

Assignees

Labels

attestationTEE / hardware attestationimplImplementation task (vs spec)specSpecification or design decisiontrack:sessionSession policy and state

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions