
Prova de conceito executável em Spring Boot que reproduz a CVE-2026-88900, a falha de desserialização Java insegura do camel-jgroups, demonstrando o comportamento afetado versus o corrigido.
Reprodutor de prova de conceito executável para a vulnerabilidade do Apache Camel em que o consumidor jgroups
desserializava em Java mensagens de cluster sem qualquer filtro. JGroupsEndpoint.createExchange(Message) — chamado para cada
mensagem que o consumidor recebe — definia o corpo do exchange a partir de org.jgroups.Message.getObject(). Para uma ObjectMessage
(o tipo enviado pelo produtor jgroups do Camel), o JGroups desserializa em Java o payload através de um ObjectInputStream à medida que
a mensagem chega, e getObject() retorna o resultado. Nenhum java.io.ObjectInputFilter era aplicado, portanto qualquer
classe serializável no classpath da aplicação recebida do cluster era instanciada e os seus callbacks de desserialização
eram executados — execução remota de código quando existe uma cadeia de gadgets utilizável. Com a pilha padrão new JChannel()
(UDP multicast, sem AUTH, sem encriptação), qualquer host que consiga alcançar o cluster pode enviar tal mensagem sem
credenciais (CWE-502).
Apenas Spring Boot. Este reprodutor inclui um único módulo Camel Spring Boot. O
camel-jgroupsnão tem uma extensãocamel-quarkus-jgroups, pelo que não existe uma contraparte Quarkus a reproduzir. O módulo Spring Boot demonstra o comportamento afetado e o corrigido.
| Runtime | Diretório | Stack |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-jgroups 4.22.0 (afetado; corrigido em 4.22.1) |
Um objeto atacante benigno — com.example.Marker, uma classe de aplicação comum que não está na allow-list
padrão da correção (java.**, javax.**, org.apache.camel.**) — é serializado para o formato de transmissão do JGroups e entregue
ao verdadeiro JGroupsEndpoint.createExchange(...), que o lê com Message.getObject() (a mesma chamada que o consumidor faz
para cada mensagem recebida). Não é necessário qualquer canal ou multicast, pelo que a verificação é determinística. Marker.readObject
altera uma flag para mostrar que o callback de desserialização é executado — uma cadeia de gadgets real executaria código malicioso nesse exato
ponto; este reprodutor não contém qualquer gadget.
com.example.Marker e createExchange lança
JGroupsException; o objeto nunca alcança a rota.Ressalva honesta (como o advisory indica): a verificação de classe da 4.22.1 / 4.18.5 é executada depois de o JGroups ter desserializado o payload, pelo que o callback
readObjectcontinua a ser executado também na build corrigida — trata-se de defesa em profundidade. Para impedir código que é executado durante a desserialização, é necessário também definir um-Djdk.serialFilterà escala da JVM e proteger o canal comAUTH+ encriptação; a 4.23.0 recusa adicionalmente iniciar um consumidor a menos que um desses controlos esteja configurado. Este reprodutor mostra o diferencial da verificação de classe; a flag de callback executado torna a ressalva visível.
cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack # affected: Marker deserialized + routed; >>> PROVEN
docker compose down
# Patched control
mvn clean package -Dcamel.version=4.22.1
java -jar target/cve-2026-88900-jgroups-deserialization-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack # fixed: JGroupsException rejects com.example.Marker; >>> Not exploited
| Propriedade | Valor |
|---|---|
| Componente | camel-jgroups (JGroupsEndpoint.createExchange) |
| CWE | CWE-502 (Desserialização de Dados Não Confiáveis) |
| Severidade | ALTA |
| Vetor de ataque | Um host capaz de alcançar o grupo multicast / porta de bind do cluster envia uma ObjectMessage maliciosa; o consumidor a desserializa sem nenhum filtro |
| Impacto | Execução remota de código no processo Camel quando uma gadget chain está no classpath; instanciação arbitrária de classes caso contrário |
| Versões Afetadas | Da 4.0.0 anterior à 4.18.5, da 4.19.0 anterior à 4.22.1 |
| Versões Corrigidas | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24676, CAMEL-25223 |
| Reportado por | h1ei1 |
Advisory: https://camel.apache.org/security/CVE-2026-88900.html
JGroupsEndpoint agora verifica a classe do corpo retornado por
Message.getObject() antes que o exchange seja roteado, por meio de uma nova opção deserializationFilter (sintaxe
jdk.serialFilter). Quando ela não está definida, um jdk.serialFilter de escopo JVM é respeitado se presente; caso
contrário, uma allow-list padrão conservadora permite java.**/javax.**/org.apache.camel.**, nega java.net.** e
rejeita todo o resto; uma mensagem recusada é reportada ao ExceptionHandler do consumidor e não é roteada. Na 4.23.0
(CAMEL-25223) o consumidor também se recusa a iniciar a menos que um controle que atue antes da desserialização
esteja configurado (um filtro de escopo JVM, a propriedade de sistema jgroups.deserialization.filter, ou um canal
AUTH+criptografia). acceptAllObjects=true restaura o comportamento antigo e é sinalizado como uma configuração
insegura.
Defina -Djdk.serialFilter na JVM que executa o consumidor (permitindo apenas as classes que suas rotas trocam pelo
cluster), proteja o canal com AUTH e SYM_ENCRYPT/ASYM_ENCRYPT por meio da opção channelProperties, e não
exponha o grupo multicast ou a porta de bind do cluster a redes não confiáveis.
Este repositório é publicado para fins educacionais e defensivos: para ajudar usuários do Apache Camel a entender a vulnerabilidade, verificar se são afetados e confirmar que a atualização a resolve. O objeto desserializado é uma classe marcadora benigna definida neste repositório; ela não contém gadget chain e não executa nenhuma ação nociva. Não use este material contra sistemas que você não possui ou opera.