AgenticWebScore
Scan

Protocol Discovery · Emerging · Medium impact

Cryptographically signed agent card

A2A v1.0 makes identity verifiable through JWS (RFC 7515).

  • Emerging
  • Medium impact
  • Draft standard
Cryptographically signed agent card — Property, Value
Property Value
Check ida2a-signed
DimensionProtocol Discovery (25%)
TierEmerging — pool 5 pts
Weight inside tier1
ImpactMedium
MaturityDraft — A published specification that is not yet ratified.
ConditionalNo
Publishing skilla2a-card-signing
StandardsRFC 7515

What the scanner requests

  • /.well-known/agent-card.json
  • /.well-known/agent.json

What is measured

The scanner fetches the A2A card and inspects its signatures array. It passes only when a signature is cryptographically verified: at least one entry is a JWS (RFC 7515) object with base64url protected and signature members whose protected header names alg, typ and kid, and the public key published at the jku URL verifies the signature over the card canonicalized per RFC 8785 with the signatures member removed, as A2A v1.0 requires. It partially passes when a signature is structurally complete but was not verified — the referenced JWKS is on another host or outside the probe set so its response was not observed, the JWKS does not publish the key, or the algorithm carries no digest this scanner can check — and it fails when a key from a published JWKS is available and the signature does not verify against it.

Reproduce it yourself

You do not have to take our word for any of this. Run the same measurement against your own domain:

              DOMAIN=https://your-domain.example
curl -sS "$DOMAIN/.well-known/agent-card.json" | jq -r '.signatures[0].protected' | python3 -c "import sys,base64,json;p=sys.stdin.read().strip();p+='='*(-len(p)%4);print(json.dumps(json.loads(base64.urlsafe_b64decode(p)),indent=2))"
            

The fix

This is the artifact to ship. It is the complete change, not a description of one.

              // npm i jose canonicalize  ->  node sign-agent-card.mjs
import { readFileSync, writeFileSync } from 'node:fs';
import canonicalize from 'canonicalize';
import { CompactSign, exportJWK, generateKeyPair } from 'jose';

const card = JSON.parse(readFileSync('agent-card.json', 'utf8'));
const { privateKey, publicKey } = await generateKeyPair('ES256');
const { signatures, ...payload } = card;   // A2A v1.0 excludes signatures
const canonical = canonicalize(payload);   // RFC 8785 canonical JSON

const jws = await new CompactSign(new TextEncoder().encode(canonical))
  .setProtectedHeader({
    alg: 'ES256', typ: 'JOSE', kid: 'key-1',
    jku: 'https://your-domain.example/.well-known/jwks.json'
  })
  .sign(privateKey);

const [protectedHeader, signature] = jws.split('.');
const signed = { ...card, signatures: [{ protected: protectedHeader, signature }] };
writeFileSync('agent-card.signed.json', JSON.stringify(signed, null, 2));
const jwk = { ...(await exportJWK(publicKey)), kid: 'key-1', use: 'sig', alg: 'ES256' };
writeFileSync('jwks.json', JSON.stringify({ keys: [jwk] }, null, 2));
            

Standards referenced

  • RFC 7515

Related checks

Related checks — Check, Tier, Impact, Same skill
Check Tier Impact Same skill
mcp-card — MCP server cardEssentialHigh—
openapi — OpenAPI definitionEssentialHigh—
oauth-discovery — OAuth discovery documentsEssentialHigh—
api-catalog — API catalogRecommendedMedium—
agent-skills — Agent Skills declarationRecommendedMedium—
a2a-card — A2A agent cardRecommendedMedium—
auth-md — /auth.md agent authentication guideEmergingMedium—
webmcp — WebMCP browser tool declarationEmergingMedium—