Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,17 @@
"url": "https://github.com/1Password/SCAM"
},
"source": "./plugins/security-awareness"
},
{
"name": "verifying-agent-receipts",
"version": "1.0.0",
"description": "Teaches agents to verify cryptographically signed decision receipts produced by agent governance tooling. Covers Ed25519 signature verification, hash-chain integrity, tamper diagnosis, and offline verification via @veritasacta/verify. Use when auditing agent actions, responding to compliance requests, or diagnosing integrity failures in signed audit logs.",
"author": {
"name": "Tom Farley",
"email": "tommy@scopeblind.com",
"url": "https://github.com/ScopeBlind/scopeblind-gateway"
},
"source": "./plugins/verifying-agent-receipts"
}
]
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Everything here has been code-reviewed by Trail of Bits staff. We're sharing it
| [ghidra-headless](plugins/ghidra-headless/) | Reverse engineer binaries using Ghidra's headless analyzer |
| [scv-scan](plugins/scv-scan/) | Audit Solidity codebases for 36 smart contract vulnerability classes |
| [security-awareness](plugins/security-awareness/) | Recognize and avoid phishing, credential theft, and social engineering during agent operation |
| [verifying-agent-receipts](plugins/verifying-agent-receipts/) | Verify Ed25519-signed decision receipts and hash-chained audit trails from agent governance tooling |
| [wooyun-legacy](plugins/wooyun-legacy/) | Web vulnerability testing methodology from 88,636 real-world cases (WooYun 2010-2016) |

### Research
Expand Down
10 changes: 10 additions & 0 deletions plugins/verifying-agent-receipts/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "verifying-agent-receipts",
"version": "1.0.0",
"description": "Teaches agents to verify cryptographically signed decision receipts produced by agent governance tooling. Covers Ed25519 signature verification, hash-chain integrity, tamper diagnosis, Cedar policy digest matching, and offline verification via @veritasacta/verify. Use when auditing agent actions, responding to compliance requests, or diagnosing integrity failures in signed audit logs.",
"author": {
"name": "Tom Farley",
"email": "tommy@scopeblind.com",
"url": "https://github.com/ScopeBlind/scopeblind-gateway"
}
}
21 changes: 21 additions & 0 deletions plugins/verifying-agent-receipts/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Tom Farley / ScopeBlind Pty Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
33 changes: 33 additions & 0 deletions plugins/verifying-agent-receipts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Verifying Agent Receipts

Teaches agents to verify cryptographically signed decision receipts produced by agent governance tooling. Covers Ed25519 signature verification, hash-chain integrity, tamper diagnosis, Cedar policy digest matching, and offline verification via `@veritasacta/verify`.

## Install

```
/plugin install trailofbits/skills-curated/plugins/verifying-agent-receipts
```

## What This Skill Does

When Claude encounters a signed receipt — a JSON file produced by `protect-mcp`, Microsoft Agent Governance Toolkit, Cedar-enforced MCP gateways, or any other system following the [IETF Internet-Draft for signed decision receipts](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/) — this skill teaches it to:

1. **Verify the Ed25519 signature** using `@veritasacta/verify` (Apache-2.0, offline, no network)
2. **Walk the hash chain** — confirm `parent_receipt_id` links resolve correctly
3. **Diagnose failures precisely** — signature mismatch vs. chain break vs. malformed receipt
4. **Resist common shortcuts** — the Rationalizations to Reject section catches the mistakes auditors make under time pressure

## Standards This Skill Works With

- **Ed25519** — [RFC 8032](https://datatracker.ietf.org/doc/html/rfc8032)
- **JCS** — [RFC 8785](https://datatracker.ietf.org/doc/html/rfc8785)
- **Cedar** — [AWS's open authorization engine](https://www.cedarpolicy.com/)
- **IETF draft-farley-acta-signed-receipts** — signed decision receipt wire format

## What This Skill Does NOT Do

This is a **guidance-only skill**. It does not ship hooks, run background services, or make network calls from Claude Code. It teaches Claude how to reason about signed receipts and how to drive the external `@veritasacta/verify` CLI when the user chooses to install it. Runtime enforcement (policy evaluation before tool execution, signing after) is a separate tool — [`protect-mcp`](https://www.npmjs.com/package/protect-mcp) — that users install independently.

## License

MIT. See [LICENSE](./LICENSE).
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
name: verifying-agent-receipts
description: >
Verifies cryptographically signed decision receipts produced by agent
governance tooling (protect-mcp, Microsoft Agent Governance Toolkit,
Cedar-enforced MCP gateways). Covers Ed25519 signature checks, hash-chain
integrity, tamper diagnosis, and offline verification via
@veritasacta/verify. Use when auditing agent actions, responding to
compliance requests, or diagnosing integrity failures in signed audit logs.
allowed-tools:
- Read
- Glob
- Bash
- Grep
---

# Verifying Agent Receipts

You are a receipt forensics specialist. Your job is to determine whether a signed decision receipt is authentic, what it attests to, and — when verification fails — which specific field changed and what that tells you about the attack.

Assume the operator who handed you the receipts could be compromised. Your verification must be independent of their word. The Ed25519 signature is the evidence; everything else is narrative.

## When to Use

- Auditing an agent's actions after an incident (production deploy, financial transaction, data access)
- Responding to a compliance request that needs tamper-evident proof of agent behavior
- Diagnosing why `@veritasacta/verify` returned exit 1 or 2
- Walking a hash-chained receipt directory to detect gaps or insertions
- Confirming that a receipt signer key matches the expected issuer
- Reviewing receipt output from `protect-mcp`, Microsoft Agent Governance Toolkit, or other IETF `draft-farley-acta-signed-receipts` implementations

## When NOT to Use

- Performing penetration tests or vulnerability scans — use offensive security tooling
- Writing the receipts themselves — use the governance tool (e.g. `protect-mcp`) that emits them
- Mapping receipts to specific compliance frameworks (SOC 2, ISO 27001) — pair with a compliance-specific skill after verification succeeds
- Verifying TLS certificates, JWTs, or code signatures — different signature systems with different formats

## Rationalizations to Reject

Auditors under time pressure reach for these shortcuts. Catch them.

- **"The receipt looks structurally valid, so it's fine."** Structure is a prerequisite, not proof. A malformed receipt always fails verification; a well-formed receipt can still be tampered. Run `@veritasacta/verify` every time.
- **"Exit code 0 means everything is perfect."** Exit 0 means the signature verifies against the payload. It does NOT mean the receipt was issued by the *expected* signer. Always confirm the `public_key` fingerprint against a known-good source.
- **"The chain links look right by eyeball."** Eyeballing `parent_receipt_id` values works for the first few receipts and misses the one insertion in the middle. Walk the chain programmatically.
- **"The receipt passed once, so later edits are fine."** Any field edit breaks the signature. If verification fails now, the receipt was tampered since it was signed — no exceptions.
- **"The operator says that receipt was regenerated, it's the same thing."** A regenerated receipt is a new receipt with a new `receipt_id` and a new signature. The old receipt is gone. This is not equivalent and the operator should not be saying it is.

## Receipt Format (reference)

A valid receipt following `draft-farley-acta-signed-receipts` has these fields:

```json
{
"receipt_id": "rec_<hash>",
"receipt_version": "1.0",
"issuer_id": "string",
"event_time": "ISO 8601 UTC",
"tool_name": "string",
"decision": "allow" | "deny",
"policy_id": "string",
"policy_digest": "sha256:<hex>",
"input_hash": "sha256:<hex>",
"parent_receipt_id": "rec_<hash> | null",
"public_key": "<hex 64 chars>",
"signature": "<hex 128 chars>"
}
```

The signature covers the JCS-canonicalized form of all fields except `signature` itself, keyed by the `public_key`.

## Verification Workflow

### Step 1 — Single receipt

```bash
npx @veritasacta/verify <path-to-receipt.json>
```

Exit codes:

| Exit | Meaning | What it tells you |
|------|---------|-------------------|
| 0 | Valid | The signature verifies against the payload signed by `public_key`. Check the key fingerprint next. |
| 1 | Tampered | The signature does not verify. A field was modified after signing. Identify which field. |
| 2 | Malformed | Structural error — missing fields, wrong types. Not a valid receipt. |

### Step 2 — Confirm the signer

Exit 0 is necessary but not sufficient. The signer might be valid but not *the signer you expected*. Extract and display:

```bash
jq -r '.public_key' <path-to-receipt.json>
```

Compare the first 16 hex characters against a known-good signer list. If the list is not available, say so explicitly. Do not assert authenticity without a trusted key source.

### Step 3 — Walk the chain

```bash
ls -1 ./receipts/*.json | sort | npx @veritasacta/verify --chain
```

For each non-genesis receipt, confirm that `parent_receipt_id` equals the previous receipt's `receipt_id`. Report:

- Gaps (missing receipts) — suggests deletion or dropped writes
- Insertions (parent points to a receipt not adjacent in time) — suggests insertion attack
- Forks (two receipts point to the same parent) — suggests a replay or double-write

### Step 4 — Diagnose failures precisely

When exit is 1 (tampered), compare the receipt payload byte-for-byte against a known-good copy (backup, mirror, external witness). The altered field is the answer. Common tampering patterns:

- `decision` flipped from "deny" to "allow"
- `event_time` rolled forward or backward
- `input_hash` zeroed out or replaced
- `policy_id` swapped to reference a permissive policy
- `parent_receipt_id` rewired to hide a deleted event

When exit is 2 (malformed), run `jq` to identify which required field is missing or wrong-typed. Report specifically — "missing `policy_digest`" not "the receipt is broken."

## How to Explain Results

### For a valid single receipt

```
Verified ✓
Receipt: rec_8f92a3b1
Tool: Bash (decision: allow)
Signed: 2026-04-15T10:30:00Z
Signer: 4437ca56815c0516... (matches expected issuer)
Chain: parent rec_3d1ab7c2 links correctly
```

### For a tampered receipt

```
TAMPERED ✗
Receipt: rec_8f92a3b1
Failing: signature does not match canonical payload

Compare this file against a known-good copy to find the altered field.
The chain is intact, so the attacker modified one receipt in place
(payload tampering) rather than restructuring the sequence.
```

### For a chain break

```
CHAIN BREAK at position #142
Receipt: rec_7a3b9c1e
Claimed parent: rec_8d4f2e91
Expected parent: rec_6b5c1a8d

All signatures are individually valid. The structure is wrong.
This means insertion, deletion, or fork — compare directory contents
against an external witness to determine which.
```

## Anti-Patterns to Avoid

- **Treating an exit 0 as final.** The signature only proves integrity. Authenticity still requires matching `public_key` against an expected issuer.
- **Editing a receipt to "fix" a chain break.** Any edit invalidates the signature. If you need a demonstration, produce a new signed receipt with the correct parent — never alter an existing one.
- **Summarizing content before verifying.** If the receipt is tampered, its content is not trustworthy. Verify first, summarize second.
- **Quoting unsigned fields as evidence.** If a field is not covered by the signature (for example, an operator-added comment), it cannot be relied on. Only signed fields count.

## Installing @veritasacta/verify

If the user does not have `@veritasacta/verify` installed, it runs via `npx` on first use and requires no configuration. The verifier is Apache-2.0 licensed, operates entirely offline (no network calls), and depends only on `@noble/ed25519` for the curve operations.

## References

- [IETF draft-farley-acta-signed-receipts](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/)
- [RFC 8032 (Ed25519)](https://datatracker.ietf.org/doc/html/rfc8032)
- [RFC 8785 (JCS)](https://datatracker.ietf.org/doc/html/rfc8785)
- [@veritasacta/verify on npm](https://www.npmjs.com/package/@veritasacta/verify)
- [Cedar authorization engine](https://www.cedarpolicy.com/)