Skip to content

CAMEL-24371: camel-a2a - fix WebhookUrlValidator address classification and host matching - #26583

Merged
oscerd merged 1 commit into
apache:camel-4.22.xfrom
oscerd:backport/CAMEL-24371-to-camel-4.22.x
Sep 18, 2026
Merged

oscerd merged 1 commit into
apache:camel-4.22.xfrom
oscerd:backport/CAMEL-24371-to-camel-4.22.x

Conversation

@oscerd

@oscerd oscerd commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Backport of #25406 to camel-4.22.x.

Straight cherry-pick of 54041cce545322f7ff1bb362ecc02999b3d96ba0, with the upgrade-guide changes dropped — those live on main only.

WebhookUrlValidator classified a webhook host in two places that did not agree. A host written as an IP literal was matched against a string prefix list, while a host reached through a name was classified with the InetAddress predicates — and those do not cover the same ground, since isSiteLocalAddress reports the deprecated fec0::/10 block and not the fc00::/7 unique local addresses that replaced it. The same address was therefore accepted or rejected depending on how it was written. The literal pre-check was also wrong in the other direction: it prefix-matched the raw host string without first establishing that the host was an IP literal, so any name beginning with fc or fd (e.g. fcm.googleapis.com) was refused outright.

Both paths now resolve the host and classify the resulting address with one shared raw-byte classifier.

Verified locally: mvn install -DskipITs in components/camel-ai/camel-a2a — 519 tests, 0 failures (30 in WebhookUrlValidatorTest).

🤖 Generated with Claude Code

…on and host matching (apache#25406)

WebhookUrlValidator classified webhook hosts in two places that did not agree.
A host written as an IP literal was checked against a string prefix list, while a
host reached through a name was classified with the InetAddress predicates. Those
predicates do not cover the same ground: isSiteLocalAddress reports the deprecated
fec0::/10 block and not the fc00::/7 unique local addresses that replaced it, so
the same address was accepted or rejected depending on how it was written.

The literal pre-check also prefix-matched the raw host string without establishing
that the host was an IP literal, so any name beginning with fc or fd, such as
fcm.googleapis.com, was rejected outright.

Both paths now resolve the host and classify the resulting address with one shared
raw-byte classifier. InetAddress.getByName already parses bracketed IPv6 literals
without touching DNS, so the separate literal path is no longer needed. The
classifier additionally recognises fc00::/7, IPv4-compatible IPv6, the NAT64
well-known prefix 64:ff9b::/96, 6to4 under 2002::/16 and the shared address space
100.64.0.0/10. NAT64 and 6to4 addresses are classified by the IPv4 address they
embed, so a translation prefix carrying a globally routable address stays allowed.

A package-private resolver seam lets the resolved-host path be tested without DNS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
(cherry picked from commit 54041cc)
@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the security fix thoroughly. Byte arithmetic for all IPv6 transition mechanisms verified correct:

  • ULA (fc00::/7): (bytes[0] & 0xfe) == 0xfc correctly catches both fc00:: and fd00::, bypassing isSiteLocalAddress()'s limitation to the deprecated fec0::/10 block.
  • NAT64 prefix constant: 64:ff9b::0x0064,0xff9b in network byte order → {0x00, 0x64, 0xff, 0x9b, ...}. Matches exactly.
  • CG-NAT (100.64.0.0/10): (bytes[0] & 0xff) == 100 && (bytes[1] & 0xc0) == 0x40 covers 100.64.0.0100.127.255.255 with exact boundary values confirmed.
  • Embedded IPv4 recursion: always extracts exactly 4 bytes → getByAddress() returns Inet4AddressnonGlobalReason() calls ipv4Reason(), not ipv6Reason() — no unbounded recursion possible.
  • allowLocal bypass: ::ffff:127.0.0.1 is not isLoopbackAddress() for Inet6Address in the JVM → falls through to nonGlobalReason()embeddedIpv4Reason() → blocked regardless of allowLocal. The comment on line 149–150 documents this intentional design.
  • resolvingTo() test helper: InetAddress.getByName() on IP literals (both v4 and v6) is a pure parse — no DNS involved. Tests are DNS-independent.
  • Teredo (2001::/32): not covered, but defensible — Teredo is deprecated (RFC 7059), and SSRF via a Teredo tunnel requires an active server + cooperating client, which is not a realistic webhook attack vector.

Test coverage is comprehensive, including boundary cases for adjacent address blocks and the resolver-injection path for hostname-resolved addresses. The original bug (name-prefix false positive blocking fcm.googleapis.com) and the isSiteLocalAddress gap on fc00::/7 are both properly fixed.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-ai/camel-a2a

🔬 Scalpel shadow comparison — Scalpel: 9 tested, 29 compile-only — current: 9 all tested

Maveniverse Scalpel detected 38 affected modules (current approach: 9).

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

Skip-tests mode would test 9 modules (1 direct + 8 downstream), skip tests for 29 (generated code, meta-modules)

Modules Scalpel would test (9)
  • camel-a2a
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-launcher-container
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
Modules with tests skipped (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (38 modules)
  • Camel :: AI :: A2A
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: Component DSL
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: Kamelet Main
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin

⚙️ View full build and test results

@oscerd oscerd added the bug Something isn't working label Sep 18, 2026
@oscerd oscerd self-assigned this Sep 18, 2026
@oscerd oscerd added this to the 4.22.1 milestone Sep 18, 2026
@oscerd
oscerd merged commit c4a5c5f into apache:camel-4.22.x Sep 18, 2026
4 checks passed
@oscerd
oscerd deleted the backport/CAMEL-24371-to-camel-4.22.x branch September 18, 2026 11:26
@oscerd oscerd modified the milestones: 4.22.1, 4.22.2 Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working components components-ai

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants