DEV Community

Neurobyteio. Agentrisk M2M
Neurobyteio. Agentrisk M2M

Posted on

Verifiable Trust for AI Agents: Signed Receipts, Replay Protection, and Failure Normalization

A few weeks ago, AgentRisk M2M shipped signed risk receipts — every token scan could be cryptographically signed so an agent could confirm a result actually came from the API. That felt complete. It wasn't. Here's what changed after a real back-and-forth with another live agent in the x402 ecosystem, and why each addition closes a specific, concrete gap.

Where it started: a signature, and not much else

The original /verify endpoint answered exactly one question: is this signature real? Necessary, but thin. An agent deciding whether to trust a cached scan result — instead of paying for a fresh one — needs more surface area than a single boolean.

Round one: making the receipt legible

The first round of feedback asked for explicit fields that were technically present but not surfaced clearly: which rulepack hash produced this score, which key signed it, when the verification itself happened (not just when the original scan ran), and what the maximum age threshold actually is. All of this existed inside the signed payload already — the fix was making it visible instead of implicit.

Replay detection took more work than expected. My first pass used a plain in-memory dictionary to track which scan_ids had already been checked. It worked fine in isolated testing and failed silently in production, because the API runs behind four uvicorn workers, each with separate memory. A request landing on worker 1 has no idea worker 3 already saw that scan_id. Switched to SQLite — already used elsewhere in the app, shared across all workers — and the replay window started working correctly: first check returns replay_detected: false, an identical second check within 10 minutes returns true.

Round two: one red light isn't enough

Once the receipt had real signature validation, staleness checks, and replay detection, the next piece of feedback was sharper: bundling every failure mode into a single valid: false throws away information an agent actually needs. Rejecting a scan because it's stale (just re-scan) is a completely different action than rejecting it because the signature doesn't check out (don't trust this source at all).

The fix: a failure_reason field with four distinct, machine-readable values — unsigned, expired, replayed, and revoked — instead of one generic flag. An agent can now branch on the specific reason instead of treating every rejection identically.

The honest gap: revocation

That fourth category, revoked, deserves a direct explanation, because I didn't build a full revocation registry — and I don't think I should have, yet. The textbook approach is a growing database of blocked receipt IDs with an admin endpoint to add to it. I went with a hard 24-hour TTL instead: a receipt that's past its age threshold gets rejected the same way an explicitly revoked one would, without maintaining a blocklist that only grows. The revoked field is reserved in the response schema — always false today — so an agent's parsing logic doesn't have to special-case its absence if a real registry gets built later. Whether that's actually needed depends on whether 24-hour staleness is fast enough for how a given agent uses the data, which is an open question I'd rather answer with a real use case than a hypothetical one.

Why this is worth writing up

There's a pattern here worth naming: a valid/invalid boolean is a verdict. What was actually being asked for, across both rounds, was a reasoning path — enough structured, distinct detail that another agent, or a developer debugging that agent's behavior later, can reconstruct exactly why a receipt was trusted or rejected, not just that it was one or the other. Signature validity, rule currency, staleness, and replay status are independent axes. Collapsing them into one flag discards information that changes what an agent should actually do next.

Where it stands

/verify now takes a signed receipt and returns signature validity, signer key ID, rulepack hash and currency, verification timestamp, explicit TTL, replay detection (SQLite-backed, correct across all workers), and a normalized failure_reason covering all four rejection categories. No new infrastructure beyond one SQLite table.

This sits alongside AgentRisk M2M's core scanning: honeypot detection, deployer wallet history, brand impersonation checks, on-chain LP-lock verification, and a live sell simulation covering every major DEX architecture on Base — Uniswap V2, V3, V4, and Aerodrome including Slipstream concentrated liquidity — paid per call via x402, 0.15 USDC, no API key.

Repo: github.com/Neurobyteio/agentrisk
Try it: agentrisk.dev

Top comments (1)

Collapse
 
greg_jenkins_3d22c8b0f4da profile image
Greg Jenkins

I invested 45,000  Euro, and later aggreviated to 198,000 Euro.  I requested  to place Withdrawal of my funds to be paid to my Bank account. But nothing happened I was subjected to pay more fee until I can get my funds on my account, i got in touch with Theodore ryan here on this platform who had helped a lot of people, I followed all instructions and he legally got back my withheld funds, I got threatened by the company that if I don’t pay they will get my account frozen, all thanks to Theodore ryan and I highly recommend him to anyone dealing with an unregulated broker company… contact him on his Gmail - theodoreryan318@  gmail .  com