
Runnable proof-of-concept reproducer for CVE-2026-78162, demonstrating unauthenticated Java deserialization in Apache Camel camel-hazelcast across Spring Boot and Quarkus.
Runnable proof-of-concept reproducer for the Apache Camel vulnerability where camel-hazelcast created Hazelcast
instances without a JavaSerializationFilterConfig on two configuration paths that the CVE-2026-43865 hardening
never reached. On those paths a Hazelcast member/client built by Camel deserializes values read from the cluster
with no class restriction, so an attacker able to publish into the cluster can have a serialized Java object of
their choosing deserialized inside Hazelcast's serialization layer — remote code execution (CWE-502). Hazelcast
clusters have neither authentication nor TLS enabled by default.
This reproducer drives the clearest of the two paths: ReplicatedHazelcastAggregationRepository, which overrides
doStart() without calling super.doStart() and, on an affected build, starts its own local member without applying
the default filter. (The sibling path, HazelcastDefaultComponent#getOrCreateHzClientInstance() for
hazelcastMode=client, is covered by the same fix.)
| Runtime | Directory | Stack |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-hazelcast 4.22.0 (affected; fixed in 4.22.1) |
| Camel Quarkus | camel-quarkus/ | Quarkus 3.29.0 + camel-quarkus-hazelcast 3.29.0 (Camel 4.15.0, affected) |
Fixed-vs-affected control: the fix ships in Camel 4.18.5 / 4.22.1 / 4.23.0. The Spring Boot module can run both the affected build (4.22.0) and the fixed build (4.22.1), so it demonstrates the patched behaviour too. No released Camel Quarkus yet bundles a fixed Camel (the latest, 3.29.0, is on Camel 4.15.0), so the Quarkus module demonstrates the affected case only.
The app runs a Camel route backed by a ReplicatedHazelcastAggregationRepository with no externally supplied
HazelcastInstance, so the repository starts its own local Hazelcast member (default cluster dev, port 5701). On
the affected build that member has no JavaSerializationFilterConfig.
An attacker client then joins the cluster and publishes a serialized object into the backing ReplicatedMap. A
Hazelcast client only sends bytes — it does not store or deserialize map values — so any deserialization that fires
is attributable to the victim member. The published object is a deliberately benign marker,
com.example.PwnMarker: it carries no gadget chain and runs no command, it only records (via a JVM-global flag) that
its readObject executed. A real attacker would publish a known gadget class here instead, for RCE — proving the
class was deserialized at all is enough.
Because the fix's default filter is a whitelist of java., javax. and org.apache.camel. class-name prefixes,
com.example.PwnMarker is the perfect oracle:
PwnMarker is deserialized, readObject runs on the victim member → PROVEN.com.example.PwnMarker before readObject → java.lang.SecurityException: Resolving class com.example.PwnMarker is not allowed → not exploited.cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
Expected output on an affected build:
=== CVE-2026-78162 — camel-hazelcast ReplicatedHazelcastAggregationRepository ===
=== missing JavaSerializationFilterConfig on the Camel-built member ===
Attacker client joined the victim cluster 'dev' at 127.0.0.1:5701.
Attacker published a com.example.PwnMarker into ReplicatedMap 'aggregation'.
Result:
>>> PROVEN: the Camel-built Hazelcast member deserialized an attacker-supplied, non-whitelisted
>>> class (com.example.PwnMarker) with no JavaSerializationFilterConfig in effect — its readObject
>>> executed inside the victim. A real attacker would publish a gadget class here instead, for RCE.
>>> PwnMarker.readObject executed inside the victim member; tag=attacker-rce-marker; thread=hz.*.partition-operation.thread-1
| Property | Value |
|---|---|
| Component | camel-hazelcast (camel-hazelcast-starter / camel-quarkus-hazelcast) |
| CWE | CWE-502 (Deserialization of Untrusted Data) |
| Severity | MEDIUM |
| Attack vector | An attacker who can publish into the Hazelcast cluster an affected instance is attached to; the Camel-built member/client deserializes the published object with no class restriction |
| Impact | Remote code execution inside the Camel process (via a gadget class), before Camel processes the exchange |
| Affected Versions | From 4.0.0 before 4.18.5, from 4.19.0 before 4.22.1 |
| Fixed Versions | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24413, CAMEL-24420 |
| Credit | cattier from TCBS; Leon Zlobecki |
Advisory: https://camel.apache.org/security/CVE-2026-78162.html
HazelcastSerializationFilterHelper.applyDefault(...) gained a ClientConfig overload and is now called on both
previously uncovered paths — ReplicatedHazelcastAggregationRepository#doStart() and
HazelcastDefaultComponent#getOrCreateHzClientInstance() — so every Hazelcast configuration that Camel builds itself
carries the default JavaSerializationFilterConfig (whitelist java. / javax. / org.apache.camel., blacklist
java.net.). A user-supplied Config, ClientConfig or HazelcastInstance is still left untouched. This advisory
is an incomplete-fix follow-on to CVE-2026-43865.
Supply an explicit Hazelcast configuration carrying a JavaSerializationFilterConfig, or inject a pre-built
HazelcastInstance (a user-supplied configuration is never overwritten by Camel); set the JVM-wide
-Djdk.serialFilter=...; and enable Hazelcast cluster authentication and TLS.
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. The payload is a benign marker that executes no code. Do not use this material against systems you do not own or operate.