SW-A2A-019: Agent card member spelled two ways
Last updated 7 November 2026
| Fact | Value |
|---|---|
| Severity | High |
| Checks | A2A agent card |
| Malicious indicator | No |
| OWASP Agentic Top 10 | ASI07 |
| OWASP MCP Top 10 | None mapped |
| NIST SP 800-53 | SI-10 (provisional mapping to SP 800-53 base controls) |
| First shipped in | Scanner 1.4.0 |
What it detects
A2A 1.0 JSON names members in camelCase, but the JSON reader of protobuf, which the A2A SDKs use, also accepts the proto field name (securityRequirements is also read as security_requirements) and keeps the later of the two. The rule reports each member that the card writes under both names. The finding is placed at the proto name and names the member by its JSON name, and the reason says what a reader does: alias_wins (a protobuf reader keeps the later, proto-named member), name_wins (it keeps the later camelCase one), refused (the member is optional or part of a choice, such as iconUrl or oauth2SecurityScheme, and a protobuf reader refuses the card) or name_kept (a removed 0.x member written both ways, where a2a-sdk 0.3 keeps the camelCase one whatever the order).
The rule works on the members the A2A 1.0 definition knows, including those inside skills, interfaces and security schemes. The removed 0.x members written in snake_case are covered too since scanner 1.5.0. A member written only with its proto name is SW-A2A-001, not this rule.
Why it matters
Two clients can read the same file and see two cards. A reader that knows only the JSON names keeps the camelCase member, and a protobuf reader keeps whichever comes later. If a card lists a security requirement and then adds security_requirements as an empty list, a protobuf client reads that no authentication is needed, while the client that checked the JSON names sees the authentication. A person who reviews the card sees both and may take the first for the one that counts. The scanner maps this rule to OWASP ASI07, Insecure Inter-Agent Communication, and to NIST SP 800-53 control SI-10, Information Input Validation.
Example
A card that lists its security requirement under the JSON name and then adds the proto name with an empty list:
.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"
]
}
],
"security_requirements": []
}The scanner reports the proto-named member as written twice, and also reports SW-A2A-007, because a protobuf reader ends up with no security requirement at all.
How to fix
Keep one name for each member, the camelCase JSON name, and delete the other. If the card is built from several sources, look for the one that adds the second name. Scan again, and if the card is signed, sign it again, because the signature is made over the card as it is served.
If it is a false positive
There is almost no harmless case. Even when both names hold the same value, a reader that treats the two differently may fail on the card, and a later edit of one name makes them differ. A tool that writes both names should be fixed at the tool. If you must keep the card for one more release, accept the finding with a note and a short expiry date.
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.