Live › vulnerability › CVE-2026-111761
Go to dashboardThe A2A Java SDK server sends task push-notification POSTs to any URL a caller supplies, with no check on destination IP, scheme, or redirects. An unauthenticated attacker can use the server as a proxy to reach loopback, internal network, and cloud metadata endpoints, and to write attacker-influenced data into internal services.
Summary written from the sources below. Check the originals before acting.
First seen by InfraStack 2026-10-23 19:11 UTC, 3h before NVD. All times on this page are UTC.
| Product | Ecosystem | Affected | Fixed in |
|---|
| org.a2aproject.sdk:a2a-java-sdk-server-common | maven | < 1.3.0.Final | 1.3.0.Final |
1.3.0.Final1.3.0.Final169.254.169.254 and internal ranges at the network layerEach row is the first time that source carried this signal. The analyst’s rows are its own findings.
org.a2aproject.sdk:a2a-java-sdk-server-common (push-notification delivery)<= 1.2.0.Final (and 1.2.1.Final-SNAPSHOT on main prior to the fix)CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N (5.8, Moderate)An unauthenticated attacker can coerce the a2a-java server into issuing HTTP requests to arbitrary internal and cloud-metadata endpoints from the server's own network position — a Server-Side Request Forgery reachable in the default deployment with no credentials, no user interaction, and a single request. The behaviour is the shipped default, not a misconfiguration.
BasePushNotificationSender (in server-common) POSTs task data to the URL stored on a task's
TaskPushNotificationConfig with no validation of the destination: no block on loopback, RFC1918,
link-local (169.254.0.0/16, including the 169.254.169.254 metadata address), unique-local,
unspecified, or multicast ranges; no scheme restriction; and no bound on redirects.
InMemoryPushNotificationConfigStore.setInfo stores the URL verbatim and
onCreateTaskPushNotificationConfig does not check it either.
Both shipped HTTP clients follow redirects (JdkA2AHttpClient → followRedirects(NORMAL),
VertxA2AHttpClient → setFollowRedirects(true)), so a creation-time URL allowlist is bypassable:
an attacker webhook answers 302 Location: http://169.254.169.254/... and the client follows it. A
hostname check is likewise defeated by DNS rebinding. A correct guard must validate the resolved
IP of every hop at connection time, not the URL string.
Demonstrated end-to-end against a running server (default wiring, unauthenticated caller):
169.254.169.254) and other internal ranges
wherever network routing permits.302 from the attacker's webhook reaches
destinations a creation-time allowlist would block, and a 302 on a POST is followed as a
GET — so GET-only endpoints such as the IMDS credentials path are reachable even though the
sender only issues POSTs. This is why a URL allowlist is not a sufficient fix; the guard must
validate the resolved IP of every redirect hop.I:L). On a redirected request the body is dropped in the
POST→GET conversion, so the body-push and the redirect-reach are separate capabilities, not
simultaneous on one request.The sender discards the fetched response and exposes no caller-visible difference between a
successful and a failed delivery (both paths return without surfacing status or body), so the base
case reads back nothing — confidentiality is scored C:N. Read-back is limited, reach is not: the
attacker still drives fully controlled requests to metadata and internal services and writes data
into them.
Against a running server with push notifications enabled (JSON-RPC transport), using only the real production classes wired the default way:
Start a local listener standing in for an internal target (no real metadata service is touched).
Send one SendMessage that starts a long-running task, with the push config inlined and its
url set to http://<internal-target>/latest/meta-data/iam/security-credentials/. Use
returnImmediately: true, header A2A-Version: 1.0, and role ROLE_USER. The URL is stored
verbatim. (Equivalent via CreateTaskPushNotificationConfig on an existing task.)
As the task emits state/artifact updates, the sender POSTs each one to the stored URL, from the server's own network position:
POST /latest/meta-data/iam/security-credentials/ HTTP/1.1
Host: 169.254.169.254
Content-Type: application/json
{"artifactUpdate":{"taskId":"...","artifact":{"parts":[{"text":"Progress update 1/20"}]}, ...}}
One SendMessage produced multiple server-side POSTs to the attacker-chosen internal path.
Verified on main (commit 72d220c, JDK 21) and unchanged on 1.2.0.Final.
Validate the resolved IP of the target and of every redirect hop before connecting: reject
loopback / RFC1918 / link-local / metadata / unique-local / unspecified / multicast; restrict the
scheme to http/https; cap redirects; and resolve-and-pin to defeat DNS rebinding. Enable by
default, with a documented opt-out for deployments that intentionally target internal webhooks. The
Go A2A SDK ships a dial-time resolved-IP guard of this shape by default.
Workaround: until a fixed release, block the host's outbound egress to the metadata endpoint and internal ranges at the network layer.
This page as .md · .json · in your agent: get_signal("CVE-2026-111761")
GitHub Advisory Database, CC-BY 4.0 · NVD data is provided by NIST and is public domain. Posts quoted belong to their authors.