{"id":"CVE-2026-111761","kind":"vulnerability","aliases":["CVE-2026-111761","GHSA-q78c-5jjq-57g8"],"related":[],"title":"A2A Java SDK has Server-Side Request Forgery (SSRF) in push-notification delivery","description":"---\n\n- **Ecosystem:** Maven\n- **Affected package:** `org.a2aproject.sdk:a2a-java-sdk-server-common` (push-notification delivery)\n- **Affected versions:** `<= 1.2.0.Final` (and `1.2.1.Final-SNAPSHOT` on `main` prior to the fix)\n- **Patched version:** _(the release that carries the fix)_\n- **CWE:** CWE-918 (Server-Side Request Forgery)\n- **Severity:** High\n- **CVSS v3.1:** `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N` (5.8, Moderate)\n\n---\n\n## Summary\n\nAn **unauthenticated** attacker can coerce the a2a-java server into issuing HTTP requests to\narbitrary internal and cloud-metadata endpoints from the server's own network position — a\nServer-Side Request Forgery reachable in the default deployment with no credentials, no user\ninteraction, and a single request. The behaviour is the shipped default, not a misconfiguration.\n\n## Details\n\n`BasePushNotificationSender` (in `server-common`) POSTs task data to the URL stored on a task's\n`TaskPushNotificationConfig` with no validation of the destination: no block on loopback, RFC1918,\nlink-local (`169.254.0.0/16`, including the `169.254.169.254` metadata address), unique-local,\nunspecified, or multicast ranges; no scheme restriction; and no bound on redirects.\n`InMemoryPushNotificationConfigStore.setInfo` stores the URL verbatim and\n`onCreateTaskPushNotificationConfig` does not check it either.\n\nBoth shipped HTTP clients follow redirects (`JdkA2AHttpClient` → `followRedirects(NORMAL)`,\n`VertxA2AHttpClient` → `setFollowRedirects(true)`), so a creation-time URL allowlist is bypassable:\nan attacker webhook answers `302 Location: http://169.254.169.254/...` and the client follows it. A\nhostname check is likewise defeated by DNS rebinding. A correct guard must validate the *resolved*\nIP of every hop at connection time, not the URL string.\n\n## Exploitation\n\nDemonstrated end-to-end against a running server (default wiring, unauthenticated caller):\n\n- **Arbitrary internal reachability.** The attacker picks the destination and the server issues\n  the request from inside the trust boundary. Delivery to loopback and to a real RFC1918 LAN\n  address was exercised at runtime; because the code applies no destination filtering of any kind,\n  the same path reaches link-local / metadata (`169.254.169.254`) and other internal ranges\n  wherever network routing permits.\n- **Allowlist + method bypass via redirect.** A `302` from the attacker's webhook reaches\n  destinations a creation-time allowlist would block, and a `302` on a `POST` is followed as a\n  `GET` — so GET-only endpoints such as the IMDS credentials path are reachable even though the\n  sender only issues `POST`s. This is why a URL allowlist is not a sufficient fix; the guard must\n  validate the resolved IP of every redirect hop.\n- **Data push into internal services.** On direct (non-redirected) delivery, each request carries\n  the task payload in the body, so internal services that ingest POST data receive\n  attacker-influenced content (basis for `I:L`). On a redirected request the body is dropped in the\n  POST→GET conversion, so the body-push and the redirect-reach are separate capabilities, not\n  simultaneous on one request.\n\nThe sender discards the fetched response and exposes no caller-visible difference between a\nsuccessful and a failed delivery (both paths return without surfacing status or body), so the base\ncase reads back nothing — confidentiality is scored `C:N`. Read-back is limited, reach is not: the\nattacker still drives fully controlled requests to metadata and internal services and writes data\ninto them.\n\n## PoC\n\nAgainst a running server with push notifications enabled (JSON-RPC transport), using only the real\nproduction classes wired the default way:\n\n1. Start a local listener standing in for an internal target (no real metadata service is touched).\n2. Send one `SendMessage` that starts a long-running task, with the push config inlined and its\n   `url` set to `http://<internal-target>/latest/meta-data/iam/security-credentials/`. Use\n   `returnImmediately: true`, header `A2A-Version: 1.0`, and role `ROLE_USER`. The URL is stored\n   verbatim. (Equivalent via `CreateTaskPushNotificationConfig` on an existing task.)\n3. As the task emits state/artifact updates, the sender POSTs each one to the stored URL, from the\n   server's own network position:\n\n   ```\n   POST /latest/meta-data/iam/security-credentials/ HTTP/1.1\n   Host: 169.254.169.254\n   Content-Type: application/json\n\n   {\"artifactUpdate\":{\"taskId\":\"...\",\"artifact\":{\"parts\":[{\"text\":\"Progress update 1/20\"}]}, ...}}\n   ```\n\nOne `SendMessage` produced multiple server-side POSTs to the attacker-chosen internal path.\nVerified on `main` (commit `72d220c`, JDK 21) and unchanged on `1.2.0.Final`.\n\n## Remediation\n\nValidate the *resolved* IP of the target and of every redirect hop before connecting: reject\nloopback / RFC1918 / link-local / metadata / unique-local / unspecified / multicast; restrict the\nscheme to `http`/`https`; cap redirects; and resolve-and-pin to defeat DNS rebinding. Enable by\ndefault, with a documented opt-out for deployments that intentionally target internal webhooks. The\nGo A2A SDK ships a dial-time resolved-IP guard of this shape by default.\n\n**Workaround:** until a fixed release, block the host's outbound egress to the metadata endpoint\nand internal ranges at the network layer.\n\n## References\n\n- CWE-918: Server-Side Request Forgery: https://cwe.mitre.org/data/definitions/918.html","summary":"The 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.","severity":"medium","cvss":5.800000190734863,"epss":0.005119999870657921,"exploited":false,"exploited_at":null,"products":[{"name":"org.a2aproject.sdk:a2a-java-sdk-server-common","fixed":["1.3.0.Final"],"affected":"< 1.3.0.Final","ecosystem":"maven"}],"ecosystems":["maven"],"tags":["a2a-java-sdk","agent-servers","ai-tooling","cwe-918","java","maven","self-hosted"],"not_affected_if":["egress-filtered","push-notifications-disabled"],"how_to_check":"Check pom.xml or the dependency lock for org.a2aproject.sdk:a2a-java-sdk-server-common at a version below 1.3.0.Final.\nConfirm whether push notifications are in use (TaskPushNotificationConfig).","fix":"Upgrade org.a2aproject.sdk:a2a-java-sdk-server-common to 1.3.0.Final.\nUntil then, block the server's outbound egress to 169.254.169.254 and internal ranges at the network layer.","status":"open","published_at":"2026-10-20T15:17:11+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","triaged_at":"2026-10-23T20:55:54+00:00","updated_at":"2026-10-23T21:57:20+00:00","category":"ai-tooling","confidence":0.8,"triage":{"at":"2026-10-23T20:55:54Z","model":"claude-haiku-5-5","output":{"fix":"Upgrade org.a2aproject.sdk:a2a-java-sdk-server-common to 1.3.0.Final.\nUntil then, block the server's outbound egress to 169.254.169.254 and internal ranges at the network layer.","reach":"internet","impact":"medium","summary":"The 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.","category":"ai-tooling","who_cares":["java","maven","a2a-java-sdk","agent-servers","self-hosted"],"confidence":0.8,"needs_auth":"no","worst_case":"Attacker makes server send requests to internal and metadata endpoints","analyst_note":"","how_to_check":"Check pom.xml or the dependency lock for org.a2aproject.sdk:a2a-java-sdk-server-common at a version below 1.3.0.Final.\nConfirm whether push notifications are in use (TaskPushNotificationConfig).\nunknown","needs_analyst":false,"not_affected_if":["push-notifications-disabled","egress-filtered"],"user_interaction":"no","needs_special_setup":"no","severity_if_unknown":"medium"},"cost_usd":0.00108,"input_tokens":4876,"output_tokens":1184,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-111761':18A,26A '-2026':17A,25A '-918':45B,143C '/16':259C '/av':155C '/latest/meta-data/iam/security-credentials':694C '1':656C '1.2.0.final':123C '1.2.1.final':125C '169.254.0.0':258C '169.254.169.254':262C,319C,417C '2':673C '3.1':154C '302':317C,432C,449C '5.8':164C '57g8':23A '5jjq':22A 'a2a':1A,29A,35B,52B,112C,174C 'a2a-java':173C 'a2a-java-sdk':34B 'a2a-java-sdk-server-common':28A,111C 'address':264C,394C 'affect':108C,121C 'agent':39B 'agent-serv':38B 'ai':42B 'ai-tool':41B 'allowlist':310C,426C,444C,484C 'answer':316C 'appli':402C 'arbitrari':182C,366C 'attack':79B,100B,169C,314C,370C,435C,530C,617C 'attacker-influenc':99B,529C 'back':601C,610C 'base':598C 'basepushnotificationsend':227C 'basi':533C 'behaviour':218C 'block':251C,446C 'bodi':520C,542C,553C,595C 'body-push':552C 'bound':277C 'boundari':384C 'bypass':312C,428C 'c':606C 'c/c':160C 'caller':66B,365C,578C 'caller-vis':577C 'capabl':562C 'carri':138C,514C 'case':599C 'check':70B,289C,327C 'class':651C 'client':295C,322C 'cloud':93B,186C 'cloud-metadata':185C 'code':401C 'coerc':171C 'common':33A,116C,231C 'confidenti':603C 'config':687C 'connect':346C 'content':532C 'control':621C 'convers':549C 'correct':335C 'creation':307C,442C 'creation-tim':306C,441C 'credenti':209C,467C 'cve':16A,24A 'cvss':151C,153C 'cwe':44B,141C,142C 'data':102B,234C,501C,527C,630C 'default':205C,222C,362C,654C 'defeat':330C 'deliveri':15A,120C,385C,511C,587C 'demonstr':353C 'deploy':206C 'destin':72B,249C,373C,404C,439C 'detail':226C 'differ':580C 'direct':507C 'discard':570C 'dns':332C 'drive':619C 'drop':544C 'ecosystem':106C 'either':291C 'enabl':641C 'end':355C,357C 'end-to-end':354C 'endpoint':95B,188C,462C 'even':471C 'everi':343C,498C 'exercis':396C 'exploit':352C 'expos':575C 'fail':586C 'fetch':572C 'filter':405C 'fix':132C,140C,489C 'follow':296C,323C,454C 'followredirect':299C 'forgeri':9A,148C,201C 'fulli':620C 'get':457C,460C,548C 'get-on':459C 'ghsa':20A 'ghsa-q78c-5jjq-57g8':19A 'guard':336C,491C 'high':150C 'hop':344C,500C 'host':50B 'hostnam':326C 'http':179C,294C 'imd':466C 'includ':260C 'influenc':101B,531C 'ingest':525C 'inlin':688C 'inmemorypushnotificationconfigstore.setinfo':280C 'insid':381C 'interact':212C 'intern':90B,104B,183C,367C,420C,504C,522C,626C,665C 'ip':73B,341C,496C 'issu':178C,377C,476C 'java':2A,30A,36B,46B,53B,113C,175C 'jdka2ahttpclient':298C 'json':643C 'json-rpc':642C 'kind':408C 'l':536C 'l/a':162C 'l/pr':157C 'lan':393C 'likewis':329C 'limit':612C 'link':256C,414C 'link-loc':255C,413C 'listen':660C 'local':257C,267C,415C,659C 'locat':318C 'long':681C 'long-run':680C 'loopback':89B,253C,387C 'main':128C 'maven':47B,107C 'metadata':94B,187C,263C,416C,624C,669C 'method':427C 'misconfigur':225C 'moder':165C 'multicast':270C 'must':337C,492C 'n':163C,607C 'n/ac':156C 'n/i':161C 'n/s':159C 'n/ui':158C 'network':91B,194C,423C 'non':509C 'non-redirect':508C 'normal':300C 'noth':602C 'notif':14A,60B,119C,640C 'oncreatetaskpushnotificationconfig':286C 'one':566C,675C 'org.a2aproject.sdk':27A,110C 'packag':109C 'patch':133C 'path':411C,468C,589C 'payload':517C 'permit':425C 'pick':371C 'poc':633C 'posit':195C 'post':61B,232C,452C,477C,526C,547C 'prior':129C 'product':650C 'proxi':86B 'push':13A,59B,118C,502C,554C,639C,686C 'push-notif':12A,58B,117C 'q78c':21A 'rang':271C,421C 'reach':88B,412C,438C,559C,613C 'reachabl':202C,368C,470C 'read':600C,609C 'read-back':608C 'real':391C,649C,668C 'rebind':333C 'receiv':528C 'redirect':76B,279C,297C,430C,499C,510C,539C,558C 'redirect-reach':557C 'releas':136C 'request':8A,147C,180C,200C,216C,379C,513C,540C,567C,622C 'resolv':340C,495C 'respons':573C 'restrict':274C 'return':590C 'rfc1918':254C,392C 'rout':424C 'rpc':644C 'run':360C,636C,682C 'runtim':398C 'scheme':74B,273C 'score':605C 'sdk':3A,31A,37B,54B,114C 'self':49B 'self-host':48B 'send':56B,674C 'sender':474C,569C 'sendmessag':676C 'separ':561C 'server':6A,32A,40B,55B,83B,115C,145C,176C,191C,198C,230C,361C,376C,637C 'server-common':229C 'server-sid':5A,144C,197C 'servic':105B,505C,523C,627C,670C 'set':692C 'setfollowredirect':302C 'sever':149C 'ship':221C,293C 'side':7A,146C,199C 'simultan':564C 'singl':215C 'snapshot':126C 'ssrf':10A 'stand':661C 'start':657C,678C 'status':593C 'still':618C 'store':238C,281C 'string':351C 'success':583C 'suffici':488C 'summari':166C 'suppli':67B 'surfac':592C 'target':666C 'task':57B,233C,241C,516C,683C 'taskpushnotificationconfig':243C 'though':472C 'time':308C,347C,443C 'tool':43B 'touch':672C 'transport':645C 'true':303C 'trust':383C 'unauthent':78B,168C,364C 'uniqu':266C 'unique-loc':265C 'unspecifi':268C 'url':64B,237C,283C,309C,350C,483C,691C 'use':81B,646C,695C 'user':211C 'v3.1':152C 'valid':246C,338C,493C 'verbatim':284C 'version':122C,134C 'vertxa2ahttpclient':301C 'via':429C 'visibl':579C 'way':655C 'webhook':315C,437C 'wherev':422C 'wire':363C,652C 'without':591C 'would':445C 'write':98B,629C","nicknames":[],"mitigations":[],"who_affected":null,"tier":"B","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-20T15:17:11+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-q78c-5jjq-57g8","url":"https://github.com/advisories/GHSA-q78c-5jjq-57g8","severity":"medium","published_at":"2026-10-20T21:06:22+00:00","modified_at":"2026-10-20T21:06:23+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","fetched_at":"2026-10-23T19:11:32+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-111761","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-111761","severity":null,"published_at":"2026-10-20T15:17:11+00:00","modified_at":"2026-10-22T22:18:01+00:00","first_seen_at":"2026-10-23T21:57:20+00:00","fetched_at":"2026-10-23T22:28:58+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}