6.3

Security requirements

Sections 13 and 14 list what a server and a client MUST and SHOULD check, and most of those checks fall on data that another agent sent.

The planner reads review.json from code-reviewer and the test-log.txt chunks from test-runner, registers a webhook at localhost:41250, and sends a bearer token to deployer. Each step crosses a boundary between two parties, and no field in A2A marks what crosses it as safe. Sections 13 and 14 of the specification say what each side must check at those boundaries.

When you finish this section, you can name the rule that applies at each boundary, and say whether the kit and the SDKs meet it. Figure 6.3 maps six boundaries in the kit, with the check at each.

Fig. 6.3trust boundaries in the kit, with a threat and a check at eachlayers
Trust boundaries in the kit Six rows, one per place where data crosses between parties in the kit, shown in the order the planner meets them. Agent card: a spoofed card sends messages elsewhere, so the planner verifies signatures over HTTPS. Parts in replies such as review.json: text written as orders, so the planner validates data parts and decides on typed fields. File and URL parts: bad files, or an agent that fetches any URL it is given, so the agent checks type, size, and URLs. Webhook URL: SSRF, so the agent rejects private hosts. Incoming notifications: forgery, so the planner checks Authorization and the task id. Stored records: secrets kept in clear, so agents redact, scope reads, and set retention. WHERE DATA CROSSES THREAT CHECK the planner checks the remote agent checks agent card /.well-known/agent-card.json spoofed card messages go to its endpoint verify signatures kid deployer-key-1, HTTPS parts in replies review.json, test-log.txt injected orders text that reads as orders validate data parts decide on typed fields file and URL parts refunds.diff, screenshot.png bad files, SSRF the agent fetches any URL check type and size validate URLs first webhook URL localhost:41250/a2a-events SSRF posts to internal hosts reject private hosts or keep an allowlist POST /a2a-events a notification arrives forged notification acts on a fake event check Authorization and that taskId is yours stored records history, configs, logs secrets kept in clear hook_secret_91d2 echoed redact, scope reads set a retention policy
Data crosses six boundaries in the kit's system, and each needs a check of its own, because A2A labels nothing it carries as safe. Read each row left to right: where data crosses, what can go wrong, and the check the specification asks for. Rows appear in the order the planner meets them. Violet checks belong to the planner and blue checks to the remote agent.

The requirements, and who meets them

The table lists each rule in §13 and §14 that binds a server or a client with a MUST or a SHOULD. The kit column says where the kit meets the rule or does not. The SDK column gives the comparison of the six official SDKs where one was made, with a link to the section that owns the detail.

RuleThe kitThe SDKs
A server must check authorization on every A2A operation requestnone per caller: the deployer needs one shared token, and the other two agents accept anyonenone includes authentication, and owner scoping differs, as security schemes tables
GetExtendedAgentCard must require authenticationthe deployer checks its bearer token before every methodnone in the core handlers, as extended cards tables
An agent must put authentication credentials in its webhook requestsAuthorization: Bearer hook_secret_91d2 on every POSTevery SDK that pushes. a2a-go and a2a-rs send only the Bearer and Basic schemes, and a2a-dotnet has no sender
An agent should validate webhook URLs against SSRFaccepts http://localhost:41250/a2a-events, because every process runs on one machinea2a-go, a2a-rs, and a2a-java reject private hosts by default. a2a-python has an opt-in validator, and the notes record no check in a2a-js
An agent should set reasonable timeouts on webhook requests and should retry10 s, and no retry5 s in a2a-js, 30 s in a2a-go and a2a-rs, the HTTP client default in a2a-python and a2a-java, and none retries
A client must check each webhook with the credentials it gavethe planner's receiver records the headers and checks nothingnot compared, and push notifications lists the receiver's duties
A client should use a unique token with one purpose for each push notification configone token per run, and a read returns it in clearthe reference SDK returns stored credentials in clear too, as push notifications shows
An agent must validate every input parameter before it processes a request. It should check file content types and reject media types that it does not expecta missing field answers -32602 with a BadRequest detail, and code-reviewer refuses a url part with image/pngthe reference SDK's media type check is off by default, as the kit README lists
An implementation must sanitize content from users against injection attacksthe planner decides on typed data fields onlynot compared
File references in A2A messages must be validated against server-side request forgery (SSRF)code-reviewer fetches no URLnot compared
Logs must not hold credentials or personal data, unless they are needed and protectedthe capture files hold dpl_test_7c1e4b and hook_secret_91d2, which are test valuesnot compared
An implementation should serve the Agent Card over HTTPS, and a client should verify signatures when the card has themthe planner fetches cards over plain HTTP and verifies nothing, and 17-signed-card.txt shows the checknot compared, and extended cards and signatures covers verification
An agent should rate-limit every operation and should log security eventsnonenot compared

Three of those rules deserve more than a row, because the data they guard arrives in every task.

Text is data, even when it reads like an order

Prompt injection: text that arrives as data and that a model on the receiving side follows as an instruction. No field of a part says how far to trust its content, and review.json was built from a diff that other people wrote.

The kit's planner decides from data parts. It reads failed from summary.json and severity from each finding in review.json, and ignores the free text beside them. Its one use of remote text is a substring test on the reviewer's question. A planner built on a model reads much more. So act only on typed fields you have checked. Keep side effects behind an approval that a person or a policy controls, as the deployer does.

URLs aim the receiver's own requests

Server-side request forgery (SSRF): a server sends a request to an address that an outside caller chose, such as an internal service. A url part invites it, and so does a webhook URL, which the agent calls for every later event of the task.

The kit's code-reviewer refuses a url part with media type image/png, because its input modes do not list it, and fetches nothing. For webhooks, the specification asks agents to reject the private ranges 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16.

They also reject localhost and link-local addresses. The kit accepts http://localhost:41250/a2a-events only because every process runs on one machine. The reference SDK's validator rejects hosts that resolve to loopback, private, link-local, reserved, multicast, or unspecified addresses. It runs only when the host turns it on. Push notifications covers the receiver's checks.

Records that outlive the task

A read of a stored configuration returns its secret in clear:

the configuration read back with its secret in clearjsonFull log
    "configs": [
      {
        "id": "92c697ef-4abc-4e86-82ba-dc6bce4077af",
        "taskId": "d7d3dceb-7333-4676-90ce-36542116a45c",
        "url": "http://localhost:41250/a2a-events",
        "token": "planner-run-0006",
        "authentication": {
          "scheme": "Bearer",
          "credentials": "hook_secret_91d2"
The ListTaskPushNotificationConfigs reply, cut to one configuration.

These reads need the task's own access check, and security schemes covers that scope. The capture files hold dpl_test_7c1e4b and hook_secret_91d2 in clear, which is safe only because they are test values. The refunds.diff part stays in the review task's history. Sensitive information in task history and artifacts must be protected as the data protection rules require. Set a retention period for all of it, as §13.4 recommends.

A2A protocol 1.0.1 · 3303592 · 2026-05-28 · Edition 2026.10