Applying Cryptographic Attestation to Agentic Applications
Agent identity proves who made a request, but not what actually happened. Dapr verifiable execution closes that gap by cryptographically signing every workflow step, verifying the chain on every state load, and carrying that proof across service and agent boundaries.
A regulator sits down with a bank's compliance team. They want proof that a specific transaction was authorized by the payment approval agent, in the sequence the runbook describes, and that nothing in the execution record has been altered in the five months since. The team pulls up the logs.
For years, that answer was enough. Today, it isn't.
Logs can be edited. Traces can be dropped. When an agent acts on behalf of a human who acted on behalf of another agent, the chain of custody has to be provable, not asserted. A regulator asking about a multi-step, multi-agent workflow isn't looking for a story about what your observability stack recorded. They're looking for evidence that would hold up if the storage was compromised, if an operator deleted a row, if someone with database access decided to smooth over an inconvenient event.
The question this article answers: what does it take to move from we logged what the agent did to we can cryptographically prove what the agent did, in what order, and that nothing has been changed after the fact?
Identity is who, attestation is what
The previous article in this series covered agent identity and how SPIFFE and mTLS give every workload a cryptographically verifiable identity that the platform can check on every call. That's who is making a request. It's load-bearing, but it isn't the whole trust model.
Identity tells you which workload authenticated a request. Verifiable execution tells you what that workload actually did, and gives you cryptographic proof that the record of what it did hasn't been altered.
That gap matters more than it looks. An authenticated action can still be tampered with in storage. A log entry signed by a valid identity, then rewritten by someone who never held that identity, still shows up looking legitimate. The original signature only proves who wrote the original bytes. It says nothing about whether what's on disk right now is what got written.
Identity, tamper-evidence, and lineage propagation are three layers of the same trust model. Most agent systems have only the first. That's the gap this article walks into.
One note on scope. Hardware-level attestation via TEEs and zero-knowledge execution proofs solves adjacent problems at a much higher cost. They're worth knowing about. They're not what Dapr provides, and they're not what most enterprises need for the workflows they're actually shipping into production. This article stays at the workflow layer, where the audit questions actually live.
What has to be true for an execution history to be trustworthy
Before naming any specific mechanism, it's worth being clear about the properties. Any verifiable execution record has to do three things.
- It has to be signed by a verifiable identity. Every entry has to be attributable to a specific workload, cryptographically. Not “the service that had permission to write here” but “this specific identity produced these specific bytes.” Without that, there's nothing to hold anyone to.
- It has to be tamper-evident. The record has to detect changes made after it was written. Signing by itself doesn't get you there. A signed record where a later step is silently modified looks fine unless someone re-verifies the whole chain, which almost no one does at the point that matters, which is when the record is being trusted, not months later during an audit.
- Provenance has to travel with the work. Real workflows cross service boundaries, hand off to other agents, and invoke tools that live in other apps. The trust in step one has to survive when a completion event comes back from step four. Otherwise, the audit trail breaks at the first hop, and everything downstream is asserted rather than proved.
All three matter, and they matter together. Signing without tamper-detection lets you prove who wrote the record, but not that it hasn't been rewritten. Tamper-detection without propagation breaks the moment the workflow hands off. A regulator asking about a multi-step, multi-agent workflow needs every one of these, not one of them.
How Dapr's verifiable execution provides each
Dapr 1.18 introduced three capabilities that together implement verifiable execution: workflow history signing, workflow history propagation, and workflow attestation. Each maps to one of the properties above.
Workflow history signing: the identity binding
Every step a workflow takes appends events to a durable history. That's what makes durable execution work in the first place. History signing extends that: every batch of events gets a cryptographic signature produced by the sidecar's SPIFFE X.509 identity, and each signature is chained to the previous one via a hash of the prior signature's bytes. The result is a cryptographic hash chain over the entire execution history, anchored to the same identity that mTLS already uses to authenticate the workload.

Fig: Every workflow history event is covered by a signature; every signature is chained to the previous one via a digest.
That's the identity binding. The signature isn't the application asserting “this record is genuine.” It's produced by the sidecar's SPIFFE key; the same key that just did the mTLS handshake to authenticate the workload. There's no parallel identity system for the audit trail. The SPIFFE ID that answers who are you is the SPIFFE ID that answers who signed this history.
Tamper-evident enforcement: the timing that matters
The signing side of this is the easy half. The harder half is when the check happens.
Dapr verifies the entire signature chain every time the workflow's state is loaded. Not on a nightly scan. Not when someone requests an audit. On every load, the chain gets walked, every signature verified, every event digest recomputed from the raw bytes stored on disk. If any check fails, the workflow doesn't run.
That timing is what makes this useful in practice. Tamper detection that happens hours later, during a scheduled scan, tells you something was corrupted. Tamper detection at load time refuses to act on corrupted state. The workflow can't move forward on a modified history because the executor won't touch it.
There's a subtler attack the signature chain has to defend against: truncation. If the chain is Sig 0 → Sig 1 → Sig 2 → Sig 3 → Sig 4 and an attacker deletes the last two along with the events they cover, the remaining Sig 0 → Sig 1 → Sig 2 is still internally valid. Dapr closes that gap through the workflow's metadata entry. It's a separate record that tracks the expected count of history events, signatures, and certificates. On every load, the runtime uses those counts to know exactly how many entries to fetch, and verification confirms that signatures cover every event from index 0 through the last one the metadata expects. If the tail was truncated, there are fewer entries on disk than the metadata claims exist, and the load fails. The same contiguity check handles deletions in the middle of the chain: event ranges have to be adjacent with no gaps, and any missing block breaks that invariant.
What happens on failure is worth being explicit about. When Dapr detects tampering on an in-flight workflow, it appends a single unsigned terminal event marked with the error type DAPR_WORKFLOW_HISTORY_TAMPERED and terminates the workflow so nothing continues to run against the poisoned state. The original state, including the tampered bytes, is preserved for forensic inspection. Nothing gets rewritten to hide the damage. The workflow surfaces as failed. The compromised state stays exactly as it was found, available to whoever's investigating.

Fig: Every load triggers full chain verification. Upon failure, Dapr halts execution and preserves the compromised state for forensic analysis.
There's a nuance here worth flagging early, because it changes rollout planning. A signed workflow can't be loaded by a non-signing host, and an unsigned workflow can't be loaded by a signing-enabled host. Signing is a one-way commitment per workflow: once turned on, it stays on for that workflow's lifetime. That's deliberate; it's what stops an attacker from disabling signing at the host level to bypass verification. But it also means turning the feature on against a running cluster requires draining unsigned workflows first, or running new work under a parallel app ID that has signing enabled from day one.
Completion attestation across boundaries
The last piece is what happens when execution crosses boundaries. A parent workflow schedules an activity. The activity runs under a different SPIFFE identity, in a different app, sometimes in a different service. When the completion event comes back, how does the parent know that the event actually came from the activity it scheduled, and not something injected into its inbox by a process with database write access?
Dapr attaches an attestation to every cross-identity completion event. Each attestation commits to the parent instance ID, the specific scheduled task ID, a digest of the input and output bytes, and the digest of the signer's certificate chain. Before the completion is allowed into the parent's inbox, the parent's runtime verifies all of it: chain of trust to a Sentry CA, SPIFFE ID matches the executing identity, the input/output digest matches what the parent actually scheduled, and the task ID resolves to a scheduling event already present in the parent's own signed history. If anything fails, the completion is rejected, and the workflow is tombstoned. If everything matches, the event enters the parent's history, where it becomes part of the signed chain the parent maintains.
SPIFFE SVIDs are short-lived by design, typically valid for hours. So how does the bank's regulator verify a signature five months later? Dapr stores the signing certificate chain alongside every signature in the workflow's own state. Verification checks whether the chain resolves to the Sentry CA, not whether the leaf certificate is still live. It's the same archival model used for code-signing timestamps.
For multi-hop propagation across apps, the same idea extends. Forwarded history chunks travel with their own per-chunk signatures, produced by the app that originally authored them, and are verified independently on ingestion.

Fig: Attestations travel with cross-identity completion events. Each hop carries its own cryptographic proof of who produced what.
The result is that the chain of custody doesn't restart at every boundary. Each hop carries its own cryptographic proof, and the receiving workflow's signed history absorbs those proofs into its own record. When the regulator asks who authorized the transaction, three hops deep, the answer isn't reconstructed from correlated logs. It's read directly from the signed lineage the parent workflow already holds.
What does this change do for compliance and incident response
The temptation is to describe verifiable execution as a monitoring improvement. It isn't. It's a category change in what audit-ready actually means.
Under the old model, compliance evidence is reconstructed; pulled from logs, correlated with traces, cross-referenced against database rows, and presented with the implicit assumption that none of the underlying data was altered between when it was produced and when it was queried. That assumption is doing a lot of work. It's exactly the assumption that a determined insider, a compromised operator, or a well-placed vulnerability would break.
Under the verifiable execution model, compliance evidence is verifiable. Any consumer of the workflow's history (including the auditor) can walk the signature chain against the same trust anchors the sidecar used, and confirm the record is exactly what the workflow produced. If it's been altered, verification fails. If it hasn't, the auditor doesn't have to trust the operations team's word on it. Cryptography is the trust.
That reframes incident response, too. When something goes wrong with an agent, for example, a bad tool call, an unexpected transaction, a decision no one can explain, the investigation has to distinguish between “the agent did this” and “the record says the agent did this.” Verifiable execution collapses those into the same statement. What the agent did is what the signed record says. The forensic team can point to the exact events, the exact signatures, the exact SPIFFE identities involved, and know none of it has been rewritten since.
Two things worth being honest about. First, this addresses the integrity of the execution record, not the quality of the decisions in it. An agent can still make a bad tool call and produce a perfectly attested record of doing so. The record proves what happened; it doesn't prove it should have. Second, verifiable execution doesn't replace observability, policy, or good testing. It's the layer underneath them. The thing that lets everything above it be trusted.
For a security engineer or AI platform lead, this is what turns what we think we know happened into evidence that holds under regulatory review. And it's often what makes the difference between an AI platform that can be greenlit for regulated workloads and one that keeps getting stuck in security review indefinitely.
Where this shows up in Diagrid Catalyst
Diagrid Catalyst is a reliable and secure platform for running agentic workloads in production, with the Dapr runtime, state stores, and message brokers managed for you. Verifiable execution is part of the runtime Diagrid Catalyst manages, not a separate feature bolted on. The SPIFFE identity that Diagrid Catalyst issues for mTLS is the identity that signs every workflow's history. The state store it manages holds the signature chain alongside the events. The audit stream going to Splunk or an existing SIEM carries the verifiable execution record with it, not just the logs.
That matters for a security engineer because the trust model doesn't require assembling four different systems to get identity, transport security, signed execution history, and audit export into the same place. It's one platform, built on open standards such as SPIFFE, mTLS, OpenTelemetry, and Dapr itself, with no proprietary identity system to buy into and no vendor-specific format for the audit trail.
Where to go next
Identity tells you who an agent is. Attestation proves what it did. Together, they're the foundation for actually governing agent behavior in production, deciding what an agent is allowed to do, based not on assertions from the calling code but on the verified provenance of what led to the request.
That's the natural next question, and it's where this series goes next: with a verifiable execution record in place, how do you turn attested provenance into enforcement policies that decide what agents can and can't do, at scale, across teams and environments? Governance and policy enforcement pick up where identity and attestation leave off.
If you want to build the working knowledge that sits underneath all of this, how Dapr's agent primitives fit together, what durable execution really means in practice, and how to compose secure, verifiable agent workflows, the Dapr Agents track at Dapr University covers it end to end.