SW-A2A-017: Agent card signed with a shared secret that only the agent can check
Last updated 7 November 2026
| Fact | Value |
|---|---|
| Severity | Medium |
| Checks | A2A agent card |
| Malicious indicator | No |
| OWASP Agentic Top 10 | ASI07 |
| OWASP MCP Top 10 | None mapped |
| NIST SP 800-53 | SI-7 (provisional mapping to SP 800-53 base controls) |
| First shipped in | Scanner 1.3.0 |
What it detects
The rule reports each signature whose outcome is unverifiable_alg. The scanner decides this from the algorithm in the protected header. HS256, HS384 and HS512 are HMAC algorithms, where the same secret signs and checks. Ed448 is a public-key algorithm that this release of the scanner does not verify. The evidence says either that a shared-secret signature can only be checked by the agent that holds the secret, or that Ed448 is not verified by this release.
The signature is not judged any further. The card's signature status stays unverified, so SW-A2A-010 does not fire on it, and the rule reports every such entry of a card, also when another entry of the same card verifies.
Why it matters
A signature is useful when a client that knows none of your secrets can check it. An HMAC signature needs the secret itself, so a client has two choices: trust the signature without checking it, or be handed the secret, which would let it sign cards in your name. The signer of the A2A SDK defaults to such an algorithm, so cards end up signed this way without anyone choosing it. The scanner maps this rule to OWASP ASI07, Insecure Inter-Agent Communication, and to NIST SP 800-53 control SI-7, Software, Firmware, and Information Integrity.
Example
A card with one signature whose protected header says HS256, an HMAC algorithm. The secret that made it was thrown away after the example was written:
.well-known/agent-card.json
{
"name": "demo-agent",
"description": "Drafts release notes from merged pull requests.",
"version": "1.0.0",
"supportedInterfaces": [
{
"url": "https://agent.example.invalid/a2a",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": {},
"securitySchemes": {
"bearer": {
"httpAuthSecurityScheme": {
"scheme": "Bearer"
}
}
},
"securityRequirements": [
{
"schemes": {
"bearer": {
"list": []
}
}
}
],
"defaultInputModes": [
"text/plain"
],
"defaultOutputModes": [
"text/plain"
],
"skills": [
{
"id": "release-notes",
"name": "Release notes",
"description": "Drafts release notes for one tag.",
"tags": [
"release"
]
}
],
"signatures": [
{
"protected": "eyJhbGciOiJIUzI1NiIsImtpZCI6InNoYXJlZC1zZWNyZXQifQ",
"signature": "_f7AbuMgV8dPGjcHddcglU5JOGYtZEgpvRxdEWEqHMI"
}
]
}The finding points at the first entry of the signatures list and says the signature can only be checked by the agent that holds the secret.
How to fix
Sign with a public-key algorithm that the scanner verifies. ES256 is a common choice, and RS256, PS256 and Ed25519 work too. Publish the public key in the file that a2a.keys names, or serve it from a key set on the card's host, and keep the private key in your signing service. Remove the HMAC signature and sign again.
If it is a false positive
If only your own services read the card and they share the secret, an HMAC signature does what you need. The scanner cannot tell that case apart, so accept the finding with a note that says who holds the secret. A published card that other organisations fetch should not use it.
If the finding is not a problem in your case, accept it with a note: in the dashboard a manager or owner can accept a finding and the note is kept with it; with the scanner on its own, add it to the baseline file with a reason and an expiry date.