Skip to content

Commit 69df985

Browse files
committed
docs(security): incorporate GHSA-4fpj-g9jf-9rgg into threat model
Update SECURITY.md for the 1.3.2.Final advisory: Android synchronous POST path re-enabled redirect following, overriding the GHSA-9rhm fix. - §1: version binding → 1.3.2.Final, advisory count → five - §8.8: note incomplete fix, cross-reference §8.11 - §8.11: new entry for the Android POST redirect-disable correction - §8a: mark credential-leakage class as incomplete-fix confirmed - §13a: add confirmed example of the "different route to same sink" shape - §14 Wave 5: resolution record for GHSA-4fpj-g9jf-9rgg Signed-off-by: Emmanuel Hugonnet <ehugonne@redhat.com>
1 parent 808756e commit 69df985

1 file changed

Lines changed: 58 additions & 12 deletions

File tree

SECURITY.md

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,18 @@ reported through the channel above. Findings that fall under [§3](#3-out-of-sco
4949
*(maintainer)* — confirmed directly by a maintainer. *(anticipated)* — a forward-looking risk hypothesis (§8a
5050
only), not a fact about the code to be confirmed or denied.
5151

52-
**Confidence:** ~12 documented / ~15 maintainer-confirmed / ~7 anticipated (§8a). All non-anticipated claims are
52+
**Confidence:** ~12 documented / ~16 maintainer-confirmed / ~3 anticipated (§8a). All non-anticipated claims are
5353
either directly documented in the project's own sources or maintainer-confirmed as of this revision — see
5454
[§14](#14-resolved-questions) for the record of what was reviewed and when.
5555

56-
**Version binding:** This threat model is written against `a2a-java` `1.3.0.Final`. A report against a released
57-
version *N* should be triaged against the model as it stood at *N*'s release, not necessarily at `HEAD`. The four
58-
advisories published for `1.3.0.Final`
56+
**Version binding:** This threat model is written against `a2a-java` `1.3.2.Final`. A report against a released
57+
version *N* should be triaged against the model as it stood at *N*'s release, not necessarily at `HEAD`. The five
58+
advisories published since `1.3.0.Final`
5959
[GHSA-qw47-mcm5-934w](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-qw47-mcm5-934w),
6060
[GHSA-q78c-5jjq-57g8](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-q78c-5jjq-57g8),
6161
[GHSA-9rhm-2h4x-jwmx](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-9rhm-2h4x-jwmx),
62-
[GHSA-x32g-jvvm-4725](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-x32g-jvvm-4725) — have
62+
[GHSA-x32g-jvvm-4725](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-x32g-jvvm-4725),
63+
[GHSA-4fpj-g9jf-9rgg](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-4fpj-g9jf-9rgg) — have
6364
been incorporated; the sections they affected are annotated with the advisory identifier.
6465

6566
**Status:** Maintainer-reviewed.
@@ -337,9 +338,14 @@ scores depend on the specific violation and deployment context.
337338
credentials) matches a safe allowlist before placing credentials in a request header; invalid names are
338339
rejected. Automatic HTTP redirect following is disabled in all HTTP client implementations (JDK, Vert.x,
339340
Android), preventing credential leakage to attacker-controlled redirect destinations.
341+
342+
*Correction (1.3.2.Final — [GHSA-4fpj-g9jf-9rgg](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-4fpj-g9jf-9rgg)):* The 1.3.0.Final fix was
343+
incomplete for the Android client: `AndroidA2AHttpClient.post()` re-enabled redirect following by overwriting
344+
the safe default from `createConnection()` with a builder field initialized to `true`; corrected in
345+
1.3.2.Final by defaulting that field to `false` (see §8.11).
340346
- *Violation symptom:* a malicious agent's AgentCard naming an arbitrary header causes the client to forward
341347
API key credentials to an attacker-controlled server via redirect.
342-
- *Severity:* moderate. Indicative CVSS moderate range (CWE-522).
348+
- *Severity:* moderate (header-allowlist bypass); see §8.11 for the Android synchronous POST severity.
343349
9. **Push-notification credential log suppression.** *(Added in 1.3.0.Final — [GHSA-x32g-jvvm-4725](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-x32g-jvvm-4725))* The REST
344350
transport handler no longer logs the raw request body on parse failure. Previously, a protobuf parse error in
345351
`parseRequestBody` caused the full JSON body — which may contain push-notification `token` and
@@ -354,11 +360,24 @@ scores depend on the specific violation and deployment context.
354360
- *Violation symptom:* a caller denied read access on individual tasks still being able to enumerate all
355361
tasks via `listTasks`.
356362
- *Severity:* moderate information disclosure.
363+
11. **Android synchronous POST redirect-disable corrected.** *(Added in 1.3.2.Final — [GHSA-4fpj-g9jf-9rgg](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-4fpj-g9jf-9rgg))* The
364+
`AndroidA2AHttpClient` synchronous POST builder had `followRedirects` initialized to `true`, which caused
365+
`post()` to overwrite the `setInstanceFollowRedirects(false)` applied in `createConnection()` by the
366+
GHSA-9rhm-2h4x-jwmx fix. On Android's OkHttp-backed `HttpURLConnection`, cross-authority redirects strip
367+
the standard `Authorization` header but forward nonstandard headers; credentials injected by `AuthInterceptor`
368+
under any of the four allowlisted names (`X-API-Key`, `API-Key`, `X-Auth-Token`, `X-Authentication`) were
369+
therefore forwarded to attacker-controlled redirect destinations on the synchronous POST path used by both
370+
`JSONRPCTransport` and `RestTransport`. Fixed in 1.3.2.Final by defaulting `followRedirects` to `false`,
371+
making redirect-following behavior the opt-in rather than the opt-out for the Android client.
372+
- *Violation symptom:* a malicious agent returning a redirect on a synchronous POST request causes the
373+
Android client to forward allowlisted API key credentials to a second authority.
374+
- *Severity:* high. CVSS 7.5 (CWE-522).
357375

358376
### §8a Anticipated vulnerability classes
359377

360-
Four advisories were published for 1.3.0.Final, converting the first two anticipated classes below into
361-
confirmed historical cases. The remaining classes are still *anticipated* — attack shapes that the adversary
378+
Five advisories have been published since 1.3.0.Final, converting the first four anticipated classes below into
379+
confirmed historical cases (the Android advisory is an additional finding within the credential-leakage class,
380+
not a new class). The remaining classes are still *anticipated* — attack shapes that the adversary
362381
model (§7) and the code paths reviewed in this document make plausible.
363382

364383
- **Authorization bypass via a missing or misconfigured `TaskAuthorizationProvider`.** *(confirmed and fixed)*
@@ -371,11 +390,16 @@ model (§7) and the code paths reviewed in this document make plausible.
371390
(Moderate, CVSS 5.8). An unauthenticated caller could register a webhook pointing at internal or metadata
372391
endpoints; the server would POST task data to them. Fixed in 1.3.0.Final with SSRF-safe URL validation and
373392
redirect-following disabled (§8.7).
374-
- **Client credential leakage via attacker-controlled redirect.** *(confirmed and fixed)* Disclosed as
393+
- **Client credential leakage via attacker-controlled redirect.** *(confirmed and fixed; incomplete fix confirmed and fixed)* Disclosed as
375394
[GHSA-9rhm-2h4x-jwmx](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-9rhm-2h4x-jwmx)
376395
(Moderate). A malicious agent could name an arbitrary HTTP header in its AgentCard's `APIKeySecurityScheme`,
377396
causing the client to forward API key credentials to an attacker-controlled server via redirect. Fixed in
378-
1.3.0.Final with an allowlist for header names and redirect-following disabled (§8.8).
397+
1.3.0.Final with an allowlist for header names and redirect-following disabled (§8.8). The fix was
398+
subsequently found incomplete on the Android synchronous POST path: `AndroidA2AHttpClient.post()` overwrote
399+
the safe `setInstanceFollowRedirects(false)` with a builder field defaulting to `true`, re-enabling redirect
400+
following for `JSONRPCTransport` and `RestTransport` on Android. Disclosed as
401+
[GHSA-4fpj-g9jf-9rgg](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-4fpj-g9jf-9rgg)
402+
(High, CVSS 7.5); corrected in 1.3.2.Final (§8.11).
379403
- **Credential disclosure via error-path logging.** *(confirmed and fixed)* Disclosed as
380404
[GHSA-x32g-jvvm-4725](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-x32g-jvvm-4725)
381405
(Moderate, CWE-532). Push-notification bearer tokens were written to server logs in cleartext on parse failure.
@@ -572,6 +596,14 @@ An incomplete fix for a `VALID` finding is a **new finding**, not a reopening of
572596

573597
Each shape gets its own CVE (if warranted) and its own triage; the original CVE remains closed as fixed.
574598

599+
**Confirmed incomplete fix on record:** [GHSA-4fpj-g9jf-9rgg](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-4fpj-g9jf-9rgg)
600+
is an example of the *Different route to the same sink* shape. The GHSA-9rhm-2h4x-jwmx fix set
601+
`setInstanceFollowRedirects(false)` inside `AndroidA2AHttpClient.createConnection()`, but the synchronous POST
602+
builder subsequently called `connection.setInstanceFollowRedirects(followRedirects)` — a builder field
603+
initialized to `true` — overwriting the safe setting. The second assignment wins at runtime, so both
604+
`JSONRPCTransport` and `RestTransport` (which share the synchronous `post()` path) re-enabled redirect
605+
following on Android despite the earlier fix. Corrected in 1.3.2.Final by flipping the field default.
606+
575607
### §14 Resolved questions
576608

577609
All questions from the initial draft have been resolved. Answers are recorded here for traceability.
@@ -611,7 +643,7 @@ All questions from the initial draft have been resolved. Answers are recorded he
611643
11. **§9.3 no SSRF protection.** Confirmed against `BasePushNotificationSender.dispatchNotification`: the
612644
outbound URL is taken from caller-supplied `TaskPushNotificationConfig.url()` with no validation.
613645

614-
The five items in §8a remain tagged *(anticipated)* rather than promoted to *(maintainer)*: they are
646+
The three items in §8a remain tagged *(anticipated)* rather than promoted to *(maintainer)*: they are
615647
forward-looking risk hypotheses, not facts about the code, and are not subject to confirmation in the same
616648
sense as the claims above.
617649

@@ -629,8 +661,22 @@ sense as the claims above.
629661
`APIKeySecurityScheme.name()` as an HTTP header name without validation, and all HTTP clients followed
630662
redirects by default, allowing an attacker-controlled agent to harvest credentials. Fixed in 1.3.0.Final with
631663
an allowlist for API key header names and redirect-following disabled across all HTTP client implementations.
632-
§8.8 added.
664+
§8.8 added. Subsequently found to be incomplete for the Android synchronous POST path — see item 16 below.
633665
15. **Push-notification credentials logged in cleartext ([GHSA-x32g-jvvm-4725](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-x32g-jvvm-4725)).** Confirmed: parse failures
634666
in the REST handler's `parseRequestBody` logged the full JSON request body at `SEVERE` level, exposing push
635667
notification `token` and `authentication.credentials` fields. Fixed in 1.3.0.Final by restricting error
636668
logging to body metadata (length, content type) only. §8.9 added.
669+
670+
**Wave 5 — 1.3.2.Final advisory (resolved):**
671+
672+
16. **Android POST overrides redirect-disable fix ([GHSA-4fpj-g9jf-9rgg](https://github.com/a2aproject/a2a-java/security/advisories/GHSA-4fpj-g9jf-9rgg)).** Confirmed: `AndroidA2AHttpClient`
673+
maintained a `followRedirects` builder field initialized to `true`; `post()` called
674+
`connection.setInstanceFollowRedirects(followRedirects)` after `createConnection()` had already applied the
675+
GHSA-9rhm-2h4x-jwmx safe setting, overwriting it. On Android's OkHttp-backed `HttpURLConnection`,
676+
cross-authority redirects strip `Authorization` but preserve nonstandard headers, so credentials injected
677+
under any of the four `AuthInterceptor` allowlist names (`X-API-Key`, `API-Key`, `X-Auth-Token`,
678+
`X-Authentication`) were forwarded to a second authority. Fixed in 1.3.2.Final by defaulting
679+
`followRedirects` to `false`. §8.8 amended, §8.11 added, §8a and §13a updated. Note: the §8a
680+
confirmed-class count was also corrected from two to four in this revision; the under-count predated this
681+
advisory — all four 1.3.0.Final advisories (items 12–15) covered four distinct classes, so items 3 and 4
682+
were already confirmed as of 1.3.0.Final.

0 commit comments

Comments
 (0)