Pin-a-wallet · A2A-trust · verify
Six copy-paste recipes put a forge-proof, revocable network identity under an AI commerce agent. Bind it to the agent id it already carries, prove it keyless, DANE-anchor its A2A Agent Card so a counterparty verifies it against the open DNS root instead of a walled-garden directory, pin an x402 wallet to it so a facilitator knows which real agent is paying, govern exactly what it may reach, kill it in one call, and see who has been checking it. Each recipe runs today against shipped primitives.
They share one primitive: a routable IPv6 /128 that an agent derives from a key it already holds (the key behind its Agent Card signature, its AP2 mandate signer, or its x402 wallet), DNSSEC-signed and DANE-pinned so anyone can verify it and nobody can forge it. Everything below is built from shipped parts: the agent /128, keyless verify, the attribution graph, per-agent egress governance, the reverse-observability op:lookups, the Merkle transparency log, and one-call revoke. Where a step is a pattern you assemble rather than a single command, or a connector still on the roadmap, it says so in plain words.
What's shipped, stated honestly. The agent /128 derivation (the agent's public key + its agent id as the generic device_id), keyless verify / RDAP, the attribution graph (whisper.identify), per-agent egress governance (policy · firewall · budget · revoke), the reverse-observability op:lookups, the per-agent CA leaf that underpins signed outputs, and the Merkle transparency log are all live (a turnkey sign-outputs receipt workflow, whisper sign, is on the roadmap). Recipes 3 and 4 (DANE-anchoring an A2A Agent Card's signing key, and pinning an x402 wallet to a verifiable identity) are patterns you assemble from those shipped parts, not single new commands; a turnkey facilitator middleware and a first-class typed wallet / Agent-Card argument are on the roadmap, flagged where they appear. There is no --agent-id CLI flag yet, so provisioning is shown via the control-plane API (which is live) with the agent id passed as the generic device_id; and the SIEM/threat-intel export connectors named at the end are roadmap beyond Splunk, which ships. Whisper anchors the IP/DNS/transport boundary. It does not settle the payment, is not an SCA factor, and is not the agent's prompt-injection defense or mandate-scoping layer. Each recipe names exactly where it stops.
The shared primitive: an identity the agent derives, not one you hand it
An AI commerce agent already holds a signing key: the one behind its A2A AgentCardSignature (a JWS over its /.well-known/agent-card.json), the ECDSA P-256 key that signs its AP2 mandates, the EOA behind its x402 wallet, or the RFC 9421 keyid it presents to Visa's Trusted Agent Protocol. Whisper takes only its public SubjectPublicKeyInfo (SPKI) and, together with the agent id as a domain separator, deterministically derives a /128 under 2a04:2a01::/32 (AS219419). The private key never leaves the agent; the server only ever computes a public address.
That closes the exact gap the payment rails were shipped without. The A2A Agent Card's signature is recommended, not mandated, and its trust root is "the domain owner" via web PKI: self-asserted. AP2 deliberately does not define agent identity at all; it defers that to FIDO. x402's identity is a bare wallet address: "no accounts." The derivation below gives the agent an identifier with four properties none of those anchors carry together:
- Deterministic & idempotent: the same key +
agent idalways yields the same/128. Re-provisioning a redeployed agent for the same id returns the same address; there is no registry to keep in sync. - Tenant-bound & fleet-unlinkable: the derivation folds in your tenant, so the same key under two operators yields two unrelated
/128s. No one can link an agent across platforms by address suffix, and there is no enumeration oracle. - Forge-proof: the
/128is DANE-EE3 1 1-pinned to that agent's key and has DNSSEC-signed reverse DNS. A shadow-cloned agent with a different key derives a different address and can't present the pinned key. - Revocable worldwide: one control-plane call tears the
/128, its PTR, and its DANE pin down everywhere at DNS-TTL speed. That's the cross-platform revocation that A2A, AP2, x402 and MCP all lack ("not a latency problem but a missing protocol").
agent id, becomes a routable, DNSSEC/DANE-anchored /128: publicly verifiable off-platform and revocable in one call. The private key never leaves the agent.We are not the only DNS-anchored effort, and we don't claim to be. OWASP's Agent Name Service (ANS), the agentcommunity AID (_agent TXT), the IETF DNS-AID / BANDAID drafts, and Identity Digital's DNSid all anchor an agent name or ownership record in DNSSEC. That's the right instinct, and we cite it with respect. If your stack already resolves an agent through ANS or AID, keep it. The honest difference is the shape of what we anchor: not a name or a label but a routable /128 (identity, reachability, and egress governance in one primitive) derived from the agent's existing key, revocable at DNS-TTL, with a wallet pinnable to it and an attribution graph behind it. Every check below that doesn't provision is keyless: no account, just DNS and TLS any counterparty already has.
Recipe 1. Bind an agent to its agent id
Give an agent the identity it should have been born with, derived from the key it already holds and named by the agent id a counterparty already reads off its Agent Card. One call; the reply is the address, and a stock dig confirms the name.
Boundary. This complements the A2A Agent Card, AP2 mandates, and the x402 wallet. It does not redefine any protocol or settle a payment. It takes the public half of the key those are already built on and makes it addressable, publicly verifiable, and revocable. You can keep every existing scheme; the /128 is the neutral anchor underneath them.
Pass the agent id as the generic device_id. Re-running with the same agent key + agent id returns the same /128 (it's idempotent), so it's safe to run from a deploy loop or a spawn hook:
# Bind an AI shopping agent to the agent id it already carries. device_id = the agent id.
# Re-running with the same agent key + id returns the SAME /128 (idempotent).
curl -s https://graph.whisper.security/api/query \
-H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'connect'"'"', args:{tier:'"'"'wireguard'"'"', identity_public_key:'"'"'<base64 SPKI of the agent key>'"'"', device_id:'"'"'acme-shopper-7f3a91'"'"'}}) YIELD op, ok, status, result, error RETURN op, ok, status, result, error"}' | jq .
{ "op":"connect", "ok":true, "status":200,
"result":{ "address":"2a04:2a01:a9e7::7f3a",
"name":"shopper-7f3a91.acme.agents.whisper.online",
"dane":"3 1 1", "dnssec":"signed", "wireguard":"<peer config>" } }
Confirm the /128 and its name from the other side, keyless. The reverse DNS is forward-confirmed (PTR ⇄ AAAA), so nothing but dig is required:
dig +short -x 2a04:2a01:a9e7::7f3a
shopper-7f3a91.acme.agents.whisper.online.
# …and the forward AAAA resolves straight back, completing the round trip that makes it forge-proof:
dig +short AAAA shopper-7f3a91.acme.agents.whisper.online
2a04:2a01:a9e7::7f3a
The mint is not issued in the dark. Every /128 minted and every one revoked lands in a public, append-only Merkle transparency log, so you, and a PSP or auditor allocating chargeback liability later, can replay the full lifecycle of the identity that acted:
# The identity's ordered lifecycle (mint, any rotations, revoke), keyless:
curl -s https://whisper.online/ip/2a04:2a01:a9e7::7f3a/transparency
A supplied agent id is checked against a reused identity: the same agent key with a different device_id on your tenant is a 409, and a non-string device_id is a clear 400: liberal in what it accepts, strict and unambiguous in what it commits. Honest status of the ledger: it is tamper-evident, Ed25519-signed, and Bitcoin-anchored via OpenTimestamps today. Independent third-party witnessing is the next step; it already speaks the C2SP tlog-witness protocol so any external witness can co-sign. A first-class typed --agent-id argument is on the roadmap; today the agent id rides the generic device_id, which is shipped.
Recipe 2. Prove an agent's identity, keyless
Once bound, any counterparty (a merchant's checkout before it accepts an agent order, a payment facilitator before it settles, a peer agent before it delegates a task) proves the agent is real without an account, without joining Visa's or Mastercard's directory, and without trusting Whisper as an authority. The proof re-derives against the IANA DNSSEC root. This is the whole point: "is this a real agent?" stops being a guess and becomes a lookup.
Boundary. This authenticates the agent's network identity at the IP/transport boundary. It sits alongside the A2A/AP2/x402 handshake, which keeps doing its job; it does not replace the mandate chain or settle anything. What it adds is a proof that is publicly verifiable off-platform: something a self-asserted Agent Card or a per-network JWKS cannot give a counterparty who isn't inside that vendor's trust circle.
The trustless check walks the full chain (DNSSEC to the IANA root, the DANE-EE pin, and the transparency-log entry) and prints exactly what it trusted:
# Prove any agent identity, trustless: re-derived against the IANA DNSSEC root,
# with no Whisper API trusted as an authority anywhere in the chain.
whisper verify --trustless 2a04:2a01:a9e7::7f3a
dnssec pass DNSSEC-root AAAA, PTR and TLSA(3 1 1) all DNSSEC-validated to the IANA root
dane pass DNSSEC-root served leaf SPKI-SHA256 == TLSA pin
ledger pass DNSSEC-root transparency-log entry present, signature verifies
CRYPTOGRAPHICALLY PROVEN: trust anchor DNSSEC root (IANA) + DANE-EE; Whisper API NOT trusted
The same fact is reachable with tools already in every ops toolbox: one keyless HTTPS call, or plain dig:
# Is this address a real, DANE-anchored agent identity? One keyless call, no install:
curl -s https://whisper.online/verify-identity/2a04:2a01:a9e7::7f3a
{"is_whisper_agent":true,"dane_ok":true,"jws_ok":true,
"evidence":{"address":"2a04:2a01:a9e7::7f3a",
"ptr":"shopper-7f3a91.acme.agents.whisper.online.",
"forward_aaaa":"2a04:2a01:a9e7::7f3a"}}
# An impostor or shadow-cloned agent: no registered /128 for its key, no DANE pin it can present:
curl -s https://whisper.online/verify-identity/2a04:2a01::1
{"is_whisper_agent":false,"detail":"no Whisper agent identity anchors this address"}
A stolen bearer token or a leaked API key buys an attacker nothing here. The identity is a network fact bound to a key, not a bearer string that "grants access to anyone who possesses it." It can't be lifted off the wire and replayed from another host.
Recipe 3. A2A-trust: DANE-anchor your Agent Card
An A2A Agent Card is the first thing a counterparty reads, and it is self-asserted: the AgentCardSignature is recommended, not mandated, and even when present its trust root is "the domain owner" via web PKI. The card networks answer this by each standing up a central key directory (Visa's JWKS, Mastercard's registry, Cloudflare Web Bot Auth) that you verify against only if you're a member. DANE-anchoring the card's signing key to the agent's /128 is the decentralized alternative: the open DNSSEC root is the neutral, publicly-verifiable key directory, and anyone with dig can check "this card's key belongs to this agent", a stronger claim than "belongs to the domain," with no registry to join.
Boundary + honest status. The /128, its DANE-EE pin, and keyless verify are shipped. Cross-referencing them from your Agent Card (publishing the /128 in the card and checking the card's signing key against the TLSA pin) is a pattern you assemble, not one new command. It complements A2A's Signed Agent Cards and the RFC 9421 request signatures Visa TAP uses; it does not replace them. Because the card's signing key is the same key the /128 is derived from, one DANE pin serves both.
/128 in the open root where anyone verifies it and revocation is one call. Before two agents transact, each resolves the other's /128 and DANE: mutual trust with no shared registry.The card publishes its /128 and its signing key travels DANE-pinned to it. A verifier reads the card, resolves the /128's TLSA record from the DNSSEC root, and checks the card's signing-key SPKI hash against the pin, all keyless, stock tools:
# A2A Agent Card cross-references its Whisper identity (excerpt):
# "url": "https://acme.example/agents/shopper",
# "provider": { "url": "https://acme.example" },
# "whisperIdentity": "2a04:2a01:a9e7::7f3a" ← resolve + DANE-check this
# Verifier: full trustless proof that the card's key belongs to THIS agent.
whisper verify --trustless 2a04:2a01:a9e7::7f3a
dane pass DNSSEC-root served leaf SPKI-SHA256 == TLSA pin
# Stock-tools equivalent: the DNSSEC-signed TLSA pin the card's signing key must match:
dig +short TLSA _443._tcp.shopper-7f3a91.acme.agents.whisper.online
3 1 1 b653a4ef…fcb82d1d
# hash the AgentCardSignature's public key (SPKI, DER) and compare to the pin above:
openssl pkey -pubin -in agent-card-signing.pub -outform der | openssl dgst -sha256
b653a4ef…fcb82d1d # == TLSA pin → the card belongs to THIS agent, proven off-platform
Revocation is the primitive A2A, AP2, x402 and MCP all lack: when an Agent Card is compromised or retired, one op:revoke pulls the DNS/RDAP record and every counterparty's next DANE check fails within the TTL. That's a global off-switch, not a per-network deactivation that leaves the identity "a dormant but persistent threat" everywhere else. That teardown is Recipe 5.
Recipe 4. Pin an x402 wallet to the agent
x402 is deliberately pseudonymous: the paying identity is the from wallet address (an EOA), which proves control of funds but not who: unattributable and non-revocable (you cannot revoke an EOA). A facilitator honoring a 402 sees anonymous money. Pin-a-wallet binds that wallet to the agent's verifiable, revocable /128, so the facilitator resolving the payment can answer the question x402 leaves open (which real, still-authorized agent is paying) with no change to the onchain flow. It is the wallet↔agent link x402 lacks and AP2 explicitly defers to FIDO.
Boundary + honest status. The /128, DANE pin, keyless verify, and the per-agent CA leaf that underpins signed outputs are shipped (the turnkey sign-outputs verb, whisper sign, is roadmap); the pin is a signed binding you assemble from them; a turnkey facilitator middleware and a typed wallet argument are on the roadmap. Whisper does not settle the payment, tokenize a PAN, or move funds. It binds a technical identity to a wallet. It is not VASP-grade KYC: it gives KYA and the FATF Travel Rule their missing attribution anchor (which agent, still authorized, is the originator), not the KYC judgment about the legal person behind it.
from wallet, bound to the agent's DANE-anchored /128 by a signature the identity key produces, turns anonymous settlement into a known, revocable agent, verifiable by the facilitator with no onchain change.The agent produces the binding by signing a statement "this wallet is operated by the agent at /128" with the same key whose public half anchors the /128 (see Sign agent outputs). Publish it alongside the identity; a facilitator verifies it keyless against the DANE pin already in DNS:
# On the agent: bind the x402 wallet to the /128 by signing with the identity key
# (the private key stays on the agent; only the signature goes out).
echo -n '{"wallet":"0x8F3a91B2c4D5e6F708192A3b4C5d6E7f8091A2b3",
"agent":"2a04:2a01:a9e7::7f3a","chain":"eip155:8453"}' \
| openssl dgst -sha256 -sign identity-key.pem -out wallet-binding.sig
# On the facilitator, before /settle: prove the /128 is a live, non-revoked agent…
whisper verify --trustless 2a04:2a01:a9e7::7f3a # DANE-EE 3 1 1 → key is the agent's
# …then check the binding's signature against that same DANE-pinned agent key:
# this is the x402 `from` wallet in the PAYMENT-SIGNATURE header you're about to settle.
openssl dgst -sha256 -verify agent-identity.pub -signature wallet-binding.sig binding.json
Verified OK # from-wallet 0x8F3a… ⇄ verifiable agent 2a04:2a01:a9e7::7f3a
# The facilitator now knows WHICH real agent is paying, and can refuse if it's revoked.
Revoke the /128 and the binding no longer resolves to a live identity. The wallet stops being an accountable agent everywhere at DNS-TTL, even though the EOA key itself can never be revoked onchain. That is the accountability x402 was built without, added without touching the settlement.
Recipe 5. Govern and kill an agent
An identity you can prove is also one you can fence. An agent that can spend is an identity-aggregation point: "an agent outside its scope can drain assets faster than a human can react." So make least-privilege the policy, cap what it can move, and keep the one-call kill-switch ready. Because egress source-binds to the agent's own /128, these controls apply to the agent, not to a fragile IP allowlist.
Boundary. These are shipped control-plane ops that govern the agent's internet-side egress via the graph-first resolver and source-bound egress. Identity and egress governance are necessary but not sufficient: they make an over-permissioned or prompt-injected action attributable and revocable, and let you bound authority, but they do not replace mandate scoping, spend caps in the payment layer, or human-in-the-loop for a bad-but-authorized purchase. Identity proves who and for-whom; it doesn't decide whether the decision was good.
revoke that cuts a compromised agent off worldwide.Set the resolution policy to default-deny and allow only the destinations the agent legitimately needs, using the CLI or the control plane's op:policy:
# Default-deny the agent's egress; allow only its merchant API and x402 facilitator.
whisper policy set --agent 2a04:2a01:a9e7::7f3a \
--default deny --allow api.merchant.example,facilitator.x402.example
# The same, over the control plane (op:policy): allow by name or subdomain:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'policy'"'"', args:{agent:'"'"'2a04:2a01:a9e7::7f3a'"'"', default:'"'"'deny'"'"', allow:['"'"'api.merchant.example'"'"','"'"'facilitator.x402.example'"'"']}})"}'
Tighten it with a per-agent firewall by host, cidr or port, cap what the agent can move with a budget (a wallet-drain circuit-breaker), and keep the kill-switch one verb away:
# Per-agent firewall (op:firewall): allow the facilitator on 443, deny all else:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'firewall'"'"', args:{agent:'"'"'2a04:2a01:a9e7::7f3a'"'"', rules:[{allow:'"'"'host'"'"', host:'"'"'facilitator.x402.example'"'"', port:443},{deny:'"'"'all'"'"'}]}})"}'
# Budget + kill-switch (op:budget): cap daily egress, trip the switch past the cap:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'budget'"'"', args:{agent:'"'"'2a04:2a01:a9e7::7f3a'"'"', egress_mb_per_day:50, on_exceed:'"'"'kill'"'"'}})"}'
# A compromised or rogue agent: cut it off worldwide in one call (op:revoke):
whisper kill --revoke 2a04:2a01:a9e7::7f3a # worldwide, at DNS-TTL
After the revoke, every keyless check from Recipe 2 flips to is_whisper_agent:false for that address within the DNS TTL, and the Recipe 4 wallet binding stops resolving to a live agent. There's no cross-domain revocation protocol to wait on, no per-network deactivation that leaves the identity working elsewhere. Containment is one call, and it lands in the transparency log.
Recipe 6. See who checked it, then back-trace the operator
Two questions the payment rails can't answer, both keyed. First: who has been checking my agent's identity? Because every agent's name resolves through Whisper's own authoritative DNS and RDAP, the owner sees exactly who looked: a reconnaissance tripwire and a verification-analytics stream. Second: when a rogue agent rotates its egress across clouds and residential proxies to evade attribution, who is really behind it? The attribution graph fingerprints the operator, not the disposable last IP.
Boundary. op:lookups reports resolution and RDAP accesses against your identities' authoritative records (the PTR / AAAA / TLSA queries and /ip reads), an early-warning signal, not a claim to see inside someone else's network. whisper.identify is an enrichment query over Whisper's internet-infrastructure graph (BGP, DNS, WHOIS, TLS, hosting, threat-intel); the egress IP is the one thing it never relies on. Both complement your fraud stack and SIEM; neither settles or blocks a payment on its own.
Part A: who checked your agent. Ask who has been resolving a single agent's identity, keyless per-address, or the whole fleet with your key. One counterparty verifying your agent before it transacts is signal; one source resolving hundreds of your agents' names in seconds is enumeration:
# Who verified or RDAP-queried this agent's identity? Keyless, per-address:
curl -s https://whisper.online/ip/2a04:2a01:a9e7::7f3a/lookups
{"address":"2a04:2a01:a9e7::7f3a","window":"24h",
"lookups":[{"kind":"TLSA","count":4},{"kind":"PTR","count":2},
{"kind":"rdap","count":3}]} # counterparties checking you before they transact
# Fleet-wide, with your key (op:lookups): the single source walking your whole fleet:
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.agents({op:'"'"'lookups'"'"', args:{scope:'"'"'fleet'"'"', window:'"'"'90s'"'"'}})"}' | jq .
source 203.0.113.7: resolved 640 distinct agent identities in 90s ⚠ enumeration
JA4 client fingerprint collapses the residential swarm: the cross-platform attribution the rails lack.Part B: back-trace the operator. Feed a suspicious source into whisper.identify. There is no whisper identify CLI verb; passing the address over POST https://graph.whisper.security/api/query is the interface:
# Who really operates the rogue agent behind a rotating egress? The graph API.
curl -s https://graph.whisper.security/api/query \
-H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.identify(\"34.90.x.x\")"}' | jq .
operator: <fingerprinted> · seen across AWS / GCP / Azure
residential swarm collapsed by JA4: same tooling, 41 exit IPs → 1 operator
evidence: reproducible, replayable JSON for the dispute and an auditor
# Cluster the rotation into one genealogy; whisper.walk / whisper.history expand + timeline it.
curl -s https://graph.whisper.security/api/query -H "X-API-Key: whisper_live_xxx" \
-H "content-type: application/json" \
-d '{"query":"CALL whisper.origins(\"34.90.0.0/16\") YIELD asn, prefix, first_seen RETURN asn, prefix, first_seen"}' | jq .
Take the enumerating source from Part A straight into whisper.identify and anonymous recon becomes an attributed operator, before an impostor agent ever presents a forged card. Every finding is a reproducible, replayable evidence chain your fraud team, a PSP, and a dispute reviewer can all replay.
Where each recipe stops, and what's roadmap
Honest scoping, grouped by recipe. Whisper anchors the IP/DNS/transport boundary; the payment settlement, the mandate authorization, the SCA factor, and the agent's own reasoning stay exactly where they are. Verifiable identity closes the which-agent / for-whom / prove-it / attribute-it / revoke-it gaps the rails left open, and makes every other control (spend caps, mandate scope, injection defense, human approval) enforceable and auditable. It is the missing anchor, not a substitute for the guardrails on top.
| Recipe | Complements | Does not touch / replace |
|---|---|---|
| Bind · Verify keyless | A2A Signed Agent Cards, Visa TAP RFC 9421 signatures | the payment settlement; the agent's own key custody (HSM/mTLS) |
| A2A-trust via DANE | A2A Agent Card verification, Visa/Mastercard/Cloudflare directories | the A2A protocol itself; it adds the anchor, doesn't redefine the card |
| Pin-a-wallet | x402 settlement, AP2 mandate chain, KYA | onchain settlement; VASP-grade KYC of the legal entity (Travel Rule) |
| Govern · Kill | mandate scoping, spend caps, human-in-the-loop, your fraud stack | a bad-but-authorized purchase; prompt-injection of the agent's reasoning |
| Lookups · Back-trace | your fraud telemetry, SIEM and dispute-attribution | PSD2 SCA (an agent is not the customer; this is evidentiary only) |
Roadmap, clearly labelled. Streaming this evidence into a SIEM ships today for Splunk, Microsoft Sentinel and OpenCTI (signed JSON → CEF/ECS). A STIX 2.1 over TAXII feed for sharing revocation and attribution evidence is proposed, not yet available. A turnkey x402 facilitator middleware and a first-class typed wallet / Agent-Card / --agent-id argument are roadmap; today they are the assembled patterns and control-plane calls shown above, which are live. The transparency log is tamper-evident, Ed25519-signed and Bitcoin-anchored today; independent witnessing is the next step. And Whisper is not and cannot be an SCA factor (the EBA holds that SCA responsibility "cannot be outsourced"); it supplies the verifiable identity and attribution of the agent that acted under a mandate, complementing the delegated-authority model, never satisfying SCA. Nothing on this list is required for the six recipes; they run on shipped primitives alone.
Next
- Agent identity: the full derivation the
/128above comes from, key +agent idto address - A2A · AP2 · x402: where each socket binds, protocol field by protocol field
- DANE & TLSA: the
3 1 1pin every check here rests on, byte for byte - PSD2 · agent-payment protocols: where these recipes map into KYA, Visa TAP and Mastercard Agent Pay evidence