Thirty-Eight Camel Advisories in One Morning, and a CVSS 10.0 That Was Already Fixed in September

Between 11:17:19Z and 12:17:11Z on 19 October 2026, NVD published 38 CVE records naming Apache Camel. All 38 carry security@apache.org as the assigning source, all are still vulnStatus: Received, and all name the same three remediation targets: 4.23.0, 4.22.1 for the 4.22.x LTS line, and 4.18.5 for the 4.18.x LTS line. The 4.14.x stream and everything older reached end of life before the work was finished and will not be fixed. Camel is the ASF’s integration framework — 6,369 stars, 5,169 forks, Apache-2.0, in continuous development since May 2009 — and it is the layer most enterprises use to move messages between the systems that matter, increasingly including the queues and HTTP endpoints that feed model and agent infrastructure.

A batch this size invites the wrong reading, which is that something went catastrophically wrong in one week. It did not. What the 38 descriptions actually record is a single sustained audit of one codebase, and read together they say something more useful than any one of them says alone. We read all 38 NVD records, the two Camel advisory pages for the headline finding, the four fix pull requests and their diffs, the 4.23 upgrade guide, and the release tags, first-hand.

The severity distribution, and the one record that matters most

One record scores 10.0 critical. Three score 8.8, five score 8.2, two score 7.5, four score 7.4, and the remaining twenty-three fall between 4.3 and 6.5. The top of the table is where the structure shows:

  • CVE-2026-78162 — 10.0, CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H, CWE-502, camel-hazelcast unrestricted Java deserialization.
  • CVE-2026-78165 — 8.8, CWE-502, camel-spring-redis: a bare JdkSerializationRedisSerializer built lazily whenever no serializer option was configured.
  • CVE-2026-88900 — 8.8, CWE-502, camel-jgroups: JGroupsEndpoint.createExchange calls org.jgroups.Message.getObject(), which Java-deserializes on the JGroups receive thread before Camel sees the exchange.
  • CVE-2026-83531 — 8.8, CWE-94 and CWE-917, the dynamic-router control endpoint compiling an expression whose language the inbound message chose.
  • CVE-2026-78164 — 8.2, camel-http/netty-http/undertow/vertx-http running CamelContext.resolvePropertyPlaceholders() over a URI supplied by message headers.
  • CVE-2026-80312 — 8.2, the camel-oauth route guard that did not stop the exchange when authentication failed.

CVE-2026-78162: the filter reached the component, not the two doors Camel builds itself

The 10.0 is not a new bug. It is the remainder of an old one. In June, CVE-2026-43865 recorded that camel-hazelcast created Hazelcast instances from a default configuration carrying no Java deserialization filter, so objects arriving over the Hazelcast cluster protocol were deserialized inside Hazelcast’s own serialization layer before Camel ever processed them. That was fixed in 4.21.0 (tagged 26 June 2026) and 4.14.8 (28 June 2026) by introducing a helper, HazelcastSerializationFilterHelper.applyDefault(Config), and calling it where Camel builds a Config.

Two places build a Hazelcast instance and did not get the call. The ASF advisory for CVE-2026-78162 names both, and the diffs confirm them exactly. The first is ReplicatedHazelcastAggregationRepository, which extends HazelcastAggregationRepository but overrides doStart() without calling super.doStart(), keeping a private copy of the bootstrap block. The fix in PR #25566 (merged 2026-08-21T18:49:05Z, +72/−0 across three files) is a single added line in that copy:

Config cfg = new XmlConfigBuilder().build();
cfg.setProperty("hazelcast.version.check.enabled", "false");
+ HazelcastSerializationFilterHelper.applyDefault(cfg);
hazelcastInstance = Hazelcast.newHazelcastInstance(cfg);

The second is HazelcastDefaultComponent#getOrCreateHzClientInstance(), which builds its own ClientConfig when hazelcastMode=client is selected and neither a referenced ClientConfig nor a hazelcastConfigUri is supplied. ClientConfig is not Config, so the helper’s single overload simply did not apply to it; PR #25595 (merged 2026-08-24T05:45:11Z) adds an applyDefault(ClientConfig) overload and refactors the shared body into a private applyDefaultFilter(SerializationConfig). The advisory states the consequence plainly, and it is the sentence worth keeping: “client-mode endpoints behaved differently from node-mode endpoints for an otherwise identical configuration.” Selecting client mode is a topology decision. Nobody chose it in order to turn a security control off, and nothing in the configuration said they had.

The blast radius is wide because Hazelcast’s defaults are permissive: the advisory notes that Hazelcast clusters have neither authentication nor TLS enabled by default. Anyone who can publish into the cluster the Camel instance is attached to can have a serialized Java object of their choosing deserialized in the Camel process, below the routing layer, with no route logic in a position to inspect it. That is what earns the 10.0, and it is the same reasoning behind the jgroups record: new JChannel() with the stock protocol stack multicasts over UDP without the AUTH protocol and without encryption, so reachability of the multicast group is the whole access-control story.

The test that is really a design note

PR #25566 adds 54 of its 72 lines as a test, and the test’s class comment is the most honest artefact in the batch. Quoted verbatim:

“Both aggregation repositories bootstrap their own Hazelcast instance when none is injected. ReplicatedHazelcastAggregationRepository overrides doStart() without calling super.doStart(), so the two bootstrap paths have to be asserted separately to keep them from drifting apart again.”

That is a maintainer writing down the actual root cause — not “we forgot a line” but “the inheritance here permits two bootstrap paths and nothing forces them to agree” — and then encoding it as an assertion rather than as a comment nobody will read. We have filed this shape repeatedly: the Arcane batch, where three CVEs were three instances of a check written per call site; WhoDB, where a per-connection authorizer was added to the SQLite connector and not to DuckDB; Gitea 28.2.0, whose five-CVE commit was titled “add missing checks to several handlers and models.” Camel’s version is distinguished only by having been caught twice on the same control, and by the fix being accompanied by a test designed to stop a third time.

The dominant class: the message decides

Strip the component names away and most of the 38 reduce to one sentence: a value the inbound message supplied was allowed to decide something the route author thought they had decided. The clearest examples, each read from its own NVD description:

  • CVE-2026-78164 (8.2) — the HTTP producer families let a message override the endpoint URI through CamelHttpUri/CamelRestHttpUri, then passed that string through property-placeholder resolution. The advisory is precise about why that is not a parsing step: resolution reaches OS environment variables, JVM system properties, every registered PropertiesFunction including the secret functions, and through camel-bean the invocation of a no-argument method on any bean in the registry. Seven call sites were affected and “a route author opted into none of this: a plain static to("http://backend/api") was sufficient.”
  • CVE-2026-83531 (8.8) — the dynamic-router control endpoint took both the subscription predicate and the name of the language to compile it with from the message, with no allow-list and no opt-in, then evaluated the result against every exchange for the life of the subscription. Removing optional expression languages from the classpath is explicitly not a workaround, because the always-present simple language was the default on the header path. The fix adds an allowPredicateFromMessage option that is off by default.
  • CVE-2026-85312 (4.8) — the saga processor consulted a header named Long-Running-Action, and the advisory names the mechanism exactly: “The name carries no Camel prefix, so it sits outside the namespace that consumer header filters block.” A naming convention was doing load-bearing security work.
  • CVE-2026-80344 (8.2) — camel-as2 took the asynchronous MDN return address from the inbound message and connected to it, presenting any credentials configured for MDN delivery to a host the remote partner chose.

The second cluster is two comparisons of the same thing that disagree. CVE-2026-80343 (8.2): the camel-netty-http security constraint matched the request path case-sensitively while dispatch did not, so flipping the case of one character left the request routed to the protected endpoint with the constraint skipped. CVE-2026-85316 (4.8): platform-http decided whether an endpoint ran in proxy mode by testing whether its path started with the string proxy, so proxyStatus and proxy-config silently became forwarding proxies. CVE-2026-85301 (4.8): the Keycloak processor validated an introspected token’s issuer only when the response carried an iss claim, and treated an absent claim as a reason to skip rather than a reason to fail.

And one record deserves separate mention because it breaks a mitigation people believe they have. CVE-2026-78165’s description states that configuring a custom redisTemplate did not close the consumer path, because RedisConsumer.setBody reads getSerializer directly rather than the serializer attached to the template. An operator who had deliberately wired a string serializer to avoid exactly this problem was still exposed. If you run camel-spring-redis, do not assume your hardening applied; the affected range for that one starts at 2.11.0, which is 2013.

The disclosure timeline, stated plainly

For the 10.0, the dates are not close. The two fixes merged on 21 and 24 August 2026; the backports to 4.22.x (#25599) and 4.18.x (#25600) merged on 24 August, within two hours of each other, all four authored by Camel PMC member Andrea Cosentino. The first release carrying the fix was 4.22.1, tagged 13 September 2026 — followed by 4.18.5 on 6 October and 4.23.0 on 11 October. The CVE was published on 19 October.

So the patch was publicly available in a shipped artefact for 36 days before an identifier existed, and in a public merged pull request for 59 days. The 4.23 upgrade guide, also public since 11 October, describes the change in behavioural terms and names the subclass problem outright. We have no reason to read that as negligence: an audit producing 38 findings needs a coordinated release, and the ASF shipped fixes first and numbered them afterwards. But the practical consequence is the one we keep recording in other projects. Anyone watching Camel’s commit stream — which is public, and which includes an upgrade-guide entry explaining precisely which bootstrap path was unfiltered — had two months of advance notice over anyone watching CVE feeds. The operator who upgrades on release cadence was protected in September and never knew. The operator who upgrades when a CVE appears has been exposed since.

What to do

Upgrade to 4.23.0, or 4.22.1 / 4.18.5 on the LTS lines. No single older version covers the batch, and if you are on 4.14.x or earlier there is no patch at all — that line is EOL and the only remediation is moving to a supported stream. Before you plan that migration, do three things that do not require a deployment window:

  1. Inventory which of the named components you actually run. The 38 records are distributed across roughly two dozen components, and most deployments use a handful. camel-hazelcast, camel-spring-redis, camel-jgroups, camel-dynamic-router, camel-oauth, camel-as2, camel-smooks and the four HTTP producer families are where the top of the severity table lives.
  2. Apply the stated interim controls where upgrade is slow. For hazelcast: supply an explicit Config carrying a JavaSerializationFilterConfig, or inject a pre-built HazelcastInstance — a user-supplied configuration is never overwritten by Camel — and turn on Hazelcast cluster authentication and TLS, which are off by default and are the control that actually bounds who can reach the sink. The ASF also publishes a JVM-wide filter (-Djdk.serialFilter=!java.net.;java.;javax.;org.apache.camel.;!*) as an alternative. For the saga header, removeHeaders("Long-Running-Action") at the trust boundary. For the dynamic router, stop forwarding untrusted transports into a dynamic-router-control endpoint.
  3. Re-derive your header trust boundary. The single highest-yield audit question this batch suggests is not about Camel: which headers on your inbound consumers are not filtered because their names do not match a prefix convention, and what does each of them decide? Long-Running-Action, CamelHttpUri and CamelDynamicRouterExpressionLanguage are three answers in one framework. Your own integration layer will have its own.

None of the 38 appears in the CISA Known Exploited Vulnerabilities catalogue, which we checked directly against the published feed (catalogue version 2026.10.16, 1,748 entries); the catalogue contains no Apache Camel records of any kind, and no exploitation has been reported. A proof-of-concept repository for CVE-2026-78162 is already circulating in exploit aggregators; we did not retrieve, inspect or run it.

Our verification was read-only. All 38 CVE identifiers, publication timestamps, vulnStatus values, the security@apache.org source identifier, CVSS 3.1 and 4.0 vectors and scores, CWE assignments, affected version ranges, descriptions and references were read first-hand from the NVD 2.0 API, and the severity distribution was computed from those records rather than quoted. The advisory pages for CVE-2026-78162 and CVE-2026-43865, including the credit to cattier of TCBS and Leon Zlobecki, were fetched directly from camel.apache.org. Pull requests #25566, #25595, #25599 and #25600 — titles, authors, creation and merge timestamps, file lists and line counts — and their complete diffs were read first-hand from the GitHub API; every line of Java and every quoted comment, including the test class comment and the 4.23 upgrade-guide text, is verbatim from those diffs. Release tags camel-4.23.0, camel-4.22.1, camel-4.18.5, camel-4.21.0 and camel-4.14.8 were resolved to their tagger and committer timestamps through the same API, as was repository metadata. KEV status was checked directly against the published catalogue. Brave Search was used for discovery only and returned automated CVE mirrors plus one vendor upgrade-guide post, with no independent technical analysis of any of the 38. We installed nothing, stood up no Camel deployment, created no Hazelcast or JGroups cluster, sent no message, and executed no proof of concept.

Sources: