
Runnable Docker proof-of-concept for CVE-2026-71569, an SSRF guard bypass in Apache Camel camel-a2a webhook validation, with probes and fix verification.
Runnable proof-of-concept reproducer for the Apache Camel vulnerability where WebhookUrlValidator
classified a push-notification webhook host in two places that did not agree:
fc00::/7 ("fc", "fd");isLoopbackAddress,
isAnyLocalAddress, isLinkLocalAddress and isSiteLocalAddress.Those predicates do not cover the same ground: isSiteLocalAddress reports the deprecated fec0::/10
block, not the fc00::/7 unique local addresses that replaced it, and the JDK carries no predicate for
them at all. The same address was therefore accepted or rejected depending on how it was written.
| Runtime | Directory | Stack |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-a2a 4.22.1 |
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.39.0 (Quarkus 3.39.0, Camel 4.22.0) |
The host name has to resolve into fc00::/7, which the compose file arranges with an extra_hosts entry
(Docker writes it into the container's /etc/hosts at start-up) — so run this through Docker, not with a
bare java -jar:
cd camel-spring-boot # or: cd camel-quarkus
mvn clean package
docker compose up -d --build
until curl -sf http://localhost:8080/exploit/ready >/dev/null; do sleep 1; done
curl -s http://localhost:8080/exploit/attack
docker compose down
Output on an affected build (identical on both runtimes):
Resolution in this environment: internal-service.example -> fd00:0:0:0:0:0:0:1
1) The unique local address as an IP LITERAL
url: https://[fd00::1]/push-notification
verdict: REFUSED - Webhook URL must not point to private/internal IPv6 ranges (SSRF protection): [fd00::1]
2) The SAME address reached through a host name
url: https://internal-service.example/push-notification
verdict: ACCEPTED, resolved to fd00:0:0:0:0:0:0:1
3) A legitimate host name that merely BEGINS with "fc" (the bug's other direction)
url: https://fcm.googleapis.com/push-notification
verdict: REFUSED - Webhook URL must not point to private/internal IPv6 ranges (SSRF protection): fcm.googleapis.com
4) CONTROL - an IPv4 private address, which isSiteLocalAddress does cover
verdict: REFUSED - ... site-local/private address ...
5) CONTROL - a link-local IPv6 literal
verdict: REFUSED - ... private/internal IPv6 ranges ...
>>> PROVEN: ...
Probes 1 and 2 are the same address, and the verdicts disagree. Probe 3 is the same inconsistency in the
other direction: the string pre-check matched the raw host without first establishing that it was an IP
literal, so any name merely beginning with fc or fd was refused outright — fcm.googleapis.com, a
perfectly ordinary push endpoint, among them. Probes 4 and 5 are controls showing the guard working where it
was written correctly.
Every probe passes allowLocal=false, which is the default (allowLocalWebhookUrls=false) and the
configuration in which the guard is expected to hold.
The webhook URL arrives as TaskPushNotificationConfig.url from the caller registering the push
notification, so it is attacker-controlled. PushNotificationDispatcher then sends the push
notification to that address, together with any Authorization header carried in the same configuration —
whose scheme and credentials the registering caller supplies.
The response is not relayed back to that caller, so what this yields is a blind outbound HTTPS
request from the Camel process to an internal address the guard was written to refuse. Reaching a service
that way additionally requires that the name resolve into fc00::/7 in the target environment, that an
HTTPS service be listening on that address, and that the TLS handshake succeed for the name being
requested — which is why the severity is assessed medium.
| Property | Value |
|---|---|
| Component | camel-a2a (WebhookUrlValidator) |
| CWE | CWE-918 (Server-Side Request Forgery) |
| Severity | Medium |
| Attack vector | A push-notification webhook URL whose host name resolves into fc00::/7 |
| Impact | A blind outbound HTTPS request, with the configured Authorization header, to an internal address the guard should have refused |
| Affected Versions | From 4.21.0 before 4.22.2 |
| Fixed Versions | 4.22.2, 4.23.0 |
| JIRA | CAMEL-24371 |
| Credit | 2122295973 at qq dot com, reported through the ASF Security Team |
Advisory: https://camel.apache.org/security/CVE-2026-71569.html
Both paths now go through InetAddress.getByName, which parses a bracketed IPv6 literal without touching
DNS, and classify the resulting address from its raw bytes with one shared classifier — so a host is
judged by the address it denotes rather than by how it was spelled. That classifier recognises fc00::/7
and the shared address space 100.64.0.0/10, as well as IPv4-compatible, NAT64 (64:ff9b::/96) and 6to4
(2002::/16) addresses whose embedded IPv4 address is not globally routable.
Fixed on main in apache/camel#25406 (54041cce), backported
to camel-4.22.x in #26583 (c4a5c5fc).
Set camel.version to 4.22.2 and run it again. Verified against 4.22.1 → 4.22.2:
1) The unique local address as an IP LITERAL
verdict: REFUSED - Webhook URL must not point to a unique local address (SSRF protection): [fd00::1]
2) The SAME address reached through a host name
verdict: REFUSED - Webhook URL must not point to a unique local address (SSRF protection): internal-service.example
3) A legitimate host name that merely BEGINS with "fc"
verdict: ACCEPTED, resolved to 216.239.38.55
Both spellings now get the same verdict, with the same message, and the false positive in probe 3 is gone too.
Place authentication in front of the A2A push-notification configuration path so the webhook URL does not
arrive from an untrusted caller, and deny egress from the Camel process to fc00::/7 at the network level.
Where the deployment has no need of IPv6, starting the JVM with -Djava.net.preferIPv4Stack=true removes
the address class the gap turns on. Note that allowLocalWebhookUrls=false is already the default and
does not by itself close the gap — probe 2 above runs with it.
This repository is published for educational and defensive purposes: to help Apache Camel users understand the vulnerability, verify whether they are affected, and confirm that upgrading resolves it. Do not use this material against systems you do not own or operate.