Share
## https://sploitus.com/exploit?id=0BCDFE2A-6AC4-5C8D-85CA-C35C1FAAEC4E
# camel-atmosphere-websocket Header Injection Reproducer (CVE-2026-55993)

This project demonstrates a **message-header injection** in Apache Camel's `camel-atmosphere-websocket`
component, tracked as **CVE-2026-55993**. The WebSocket consumer copies the connection's query parameters onto
the Camel Exchange **without any `HeaderFilterStrategy`**, so a client can inject Camel control headers โ€” notably
`CamelHttpUri` โ€” simply by adding them to the WebSocket URL's query string:

```java
// WebsocketConsumer.sendEventNotification (affected 4.18.2) โ€” query params -> Exchange headers, unfiltered
for (Map.Entry param : queryMap.entrySet()) {
    exchange.getIn().setHeader(param.getKey(), param.getValue());
}
// where queryMap = getQueryMap(request.getQueryString())  (a naive, non-filtering parser)
```

When the route bridges this consumer into an HTTP producer, an injected `CamelHttpUri` **overrides the producer's
target URI** โ€” server-side request forgery. The camel-http producer also calls `resolvePropertyPlaceholders()` on
that attacker-controlled URI, so an injected `{{...}}` reference is expanded to its real value and sent out โ€”
disclosing environment variables, application properties, or vault secrets.

This PoC demonstrates the impact as **SSRF plus secret disclosure (CWE-20 โ†’ CWE-918 + CWE-200)**. It is one of
three sibling components fixed together under CAMEL-23532 (with `camel-vertx-websocket`, CVE-2026-46726, and
`camel-iggy`, CVE-2026-55994).

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

## Vulnerability Summary

| Property | Value |
|----------|-------|
| **Component** | `camel-atmosphere-websocket` |
| **Affected Class** | `org.apache.camel.component.atmosphere.websocket.WebsocketConsumer` (`getQueryMap()` / `sendEventNotification()` map query params to headers with no filter) |
| **CWE** | CWE-20 (Improper Input Validation) โ†’ CWE-918 (SSRF) + CWE-200 (Information Exposure) |
| **Impact** | Unauthenticated SSRF and disclosure of secrets via property-placeholder resolution on the injected URI |
| **Preconditions** | A route bridges an `atmosphere-websocket` consumer into an HTTP producer; the servlet runs with `events=true` |
| **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-23532 (PR [apache/camel#23285](https://github.com/apache/camel/pull/23285)) |
| **Credit** | Kamalpreet Singh |

> The fix applies the inherited `HttpHeaderFilterStrategy` to the inbound mapping, filtering `Camel*` / `camel*`
> headers case-insensitively so they can no longer be injected through the WebSocket query string.

## How this reproducer exercises the real vulnerable code

The two vulnerable members of `WebsocketConsumer` are run **unchanged, with an attacker-controlled query string**:

1. the real `WebsocketConsumer.getQueryMap(String)` โ€” the naive, non-filtering parser that turns the WebSocket
   connection's query string into a map;
2. the real `WebsocketConsumer.sendEventNotification(...)` โ€” which copies every entry of that map onto the
   Exchange as a header, with no `HeaderFilterStrategy`.

The resulting Exchange flows through the **real route** to the **real camel-http producer**, so the SSRF and the
`{{...}}` property-placeholder disclosure are genuine.

> **Why the WebSocket transport is not used directly.** In this component version (Camel 4.18.2 โ†’ Atmosphere
> 3.1.0), a WebSocket is served over **JSR-356**, whose upgrade is handled by the servlet container and
> **bypasses `CamelWebSocketServlet.service()`** โ€” the only place that copies the connection's query string into
> the consumer's `queryMap`. `sendEventNotification` reads that (empty) map, never the query on the WebSocket
> session, so the injection cannot be delivered through a live JSR-356 WebSocket in this Atmosphere version.
> (Atmosphere 3.1.0 ships only JSR-356 / Servlet30 / BlockingIO / Netty support โ€” no servlet-based WebSocket
> transport that would populate `queryMap`.) This reproducer therefore invokes the two real vulnerable methods
> directly with the attacker's query string; the sibling `camel-vertx-websocket` PoC (CVE-2026-46726) drives the
> identical defect through a live WebSocket, because that component maps the query on every message.

## The victim route

```java
from("atmosphere-websocket:///feed")
    .to("http://localhost:8080/legit-backend?throwExceptionOnFailure=false");
```

The route author's only intended target is `/legit-backend`; the injected `CamelHttpUri` overrides it.

## Repository layout

```
CVE-2026-55993/
โ”œโ”€โ”€ pom.xml                 # camel-atmosphere-websocket + camel-http 4.18.2
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ docker-compose.yml      # single self-contained service
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ src/main/
    โ”œโ”€โ”€ java/com/example/
    โ”‚   โ”œโ”€โ”€ Application.java
    โ”‚   โ”œโ”€โ”€ VictimRoute.java        # atmosphere-websocket:///feed -> http://localhost:8080/legit-backend
    โ”‚   โ”œโ”€โ”€ SinkController.java     # SSRF collector: /legit-backend, /internal/secret, /collect/{secret}
    โ”‚   โ””โ”€โ”€ ExploitController.java  # drives the real getQueryMap + sendEventNotification with an injected query
    โ””โ”€โ”€ resources/
        โ””โ”€โ”€ application.properties  # app.secret=... (leaked via placeholder resolution)
```

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

```
1) Legitimate WebSocket connection (no query params)
     reached /legit-backend: true
     reached /internal/secret: false

2) Injected query 'CamelHttpUri=http://localhost:8080/internal/secret'  (SSRF)
     server-side request reached /internal/secret: true

3) Injected query 'CamelHttpUri=http://localhost:8080/collect/{{app.secret}}'  (secret disclosure)
     attacker's collector received leak = SUPER-SECRET-abc123
     equals the app's real secret: true

>>> SSRF=true, secret-disclosure=true
```

## Recommended Fix

Upgrade to **4.14.8 / 4.18.3 / 4.21.0** (CAMEL-23532). After upgrading, the consumer filters `Camel*` headers from
the WebSocket query string, so `CamelHttpUri` and other control headers can no longer be injected.

## Mitigation

Until upgrading, do not bridge an `atmosphere-websocket` consumer directly into an HTTP producer without stripping
Camel control headers first (for example `removeHeaders("CamelHttp*")`), and set the producer's target from a
trusted source (or use `bridgeEndpoint=true`).

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