
Prova de conceito executável para CVE-2026-88789, demonstrando XXE e SSRF no Apache Camel Quarkus camel-quarkus-support-xalan através do XSLT TransformerFactory.
TransformerFactory Xalan forçado descarta as restrições de acesso externo do JAXPReprodutor executável de prova de conceito para a vulnerabilidade do Apache Camel Quarkus em que a extensão de suporte a XSLT
(camel-quarkus-support-xalan) fornece seu próprio TransformerFactory baseado em Xalan ao componente xslt
e o registra como padrão do JAXP. O Xalan-J 2.7.x é anterior ao JAXP 1.5 e não consegue honrar
javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD nem ACCESS_EXTERNAL_STYLESHEET — setAttribute() lança
IllegalArgumentException para ambos —, portanto as restrições de acesso externo que o Apache Camel aplica ao
TransformerFactory que cria nunca estiveram em vigor.
| Runtime | Diretório | Stack |
|---|---|---|
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.36.0 (Quarkus 3.36.0, Camel 4.20.0) |
Somente Camel Quarkus. O código vulnerável é uma extensão do Camel Quarkus, não um componente do Camel. O Camel puro e o Camel Spring Boot usam o
TransformerFactorydo JDK, que honra ambos os atributos, então não há nada a reproduzir neles — este repositório, portanto, não tem variantecamel-spring-boot/.
Um atacante que fornece o documento XML sendo transformado pode ler arquivos locais ou alcançar locais de rede internos por meio de uma declaração de entidade externa nesse documento.
cd camel-quarkus
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
Saída esperada em uma build afetada (resumida — o driver executa seis sondagens, veja
camel-quarkus/README.md):
1) xslt endpoint, body is a StreamSource, external entity -> file:///tmp/cve-2026-88789-secrets/db-password.txt
transformation result: [db.password=LOCAL-FILE-s3cr3t-99]
local file contents in the output: true
2) xslt endpoint, body is a StreamSource, external entity -> http://127.0.0.1:8080/internal/secret
transformation result: [INTERNAL-SECRET-s3cr3t-42]
internal endpoint response in the output: true
4) CONTROL - same document as a String body (Camel converts it to a SAXSource itself)
transformation result: []
local file contents in the output: false
5) TransformerFactory.newInstance() anywhere in the application
factory: org.apache.camel.quarkus.support.xalan.XalanTransformerFactory
setAttribute(ACCESS_EXTERNAL_DTD, ""): REFUSED, IllegalArgumentException: ...
identity transform of the same document: [... <data>db.password=LOCAL-FILE-s3cr3t-99</data> ...]
Requests the XML parser made to internal endpoints on its own: [GET /internal/secret, GET /internal/leak.dtd]
>>> PROVEN: ...
Verificado também contra o Camel Quarkus 3.40.0: toda sondagem que vazava fica silenciosa, os endpoints internos
não recebem nenhuma requisição, e o driver imprime NOT reproduced.
No caminho do componente xslt, apenas corpos que chegam ao transformer já como um
javax.xml.transform.Source são afetados. Corpos de outros tipos — String, byte[], InputStream — são
convertidos pelo Apache Camel em um SAXSource com entidades externas e carregamento de DTD externo desabilitados, e
não são afetados. A sondagem 4 no reprodutor é esse caminho seguro, lado a lado com o inseguro.
Como a factory também é registrada como padrão do JAXP (a extensão de suporte fornece
META-INF/services/javax.xml.transform.TransformerFactory), qualquer outro código na aplicação que obtenha
uma factory por meio de TransformerFactory.newInstance() perde as mesmas restrições, sem erro. É por
isso que o advisory lista extensões que nunca transformam nada por si mesmas:
| Extensão | Exposição |
|---|---|
camel-quarkus-xslt | o caminho do componente xslt e o padrão do JAXP |
camel-quarkus-xslt-saxon | o padrão do JAXP |
camel-quarkus-tika | o padrão do JAXP |
camel-quarkus-xmlsecurity | o padrão do JAXP |
| Propriedade | Valor |
|---|---|
| Componente | camel-quarkus-support-xalan (extensão de suporte a XSLT) |
| CWE | CWE-611 (Restrição Imprópria de Referência a Entidade Externa XML) |
| Severidade | Alta |
| Vetor de ataque | Uma entidade externa ou DTD externo declarado no documento XML sendo transformado, onde o corpo chega ao endpoint xslt já como um javax.xml.transform.Source |
| Impacto | Ler arquivos locais; emitir requisições para locais de rede internos (SSRF) |
| Versões Afetadas | De 3.2.0 antes de 3.33.3, de 3.34.0 antes de 3.40.0 |
| Versões Corrigidas | 3.33.3 (fluxo LTS), 3.40.0 |
| Issue no GitHub | apache/camel-quarkus#9115 |
| Crédito | Descoberto por análise interna, usando Claude Security Tool |
Advisory: https://camel.apache.org/security/CVE-2026-88789.html
XalanTransformerFactory agora aplica as restrições por conta própria em vez de depender de atributos que o Xalan não
consegue honrar:
XMLReader que não resolve nem entidades gerais externas nem
entidades de parâmetro externas e não carrega DTDs externos — a mesma configuração que o
XmlConverter.createSAXParserFactory() do Apache Camel usa para os corpos que o camel-xslt converte em um SAXSource por conta própria.
Um SAXSource que carrega um XMLReader configurado pelo chamador é usado como está, e DOMSource e StAXSource
já estão analisados.document() são negados a menos que o próprio
URIResolver da aplicação os resolva, e a restrição é instalada em todo ponto de entrada que entrega algo
para transformar, incluindo os pontos de entrada de push SAX cujos transformers o Xalan não copia o resolver da factory
para eles. Aplicações que definem seu próprio resolver — o camel-xslt o faz em toda exchange — continuam
sobrescrevendo-o como antes.Corrigido em main em
9a570b64 e
9dd11779,
com backport para 3.33.x em
ad9c5236 e
3d886769.
javax.xml.transform.Source construído a partir de entrada não confiável para um endpoint xslt. Deixe o
corpo da mensagem como String, byte[] ou InputStream para que o Apache Camel o converta em um SAXSource com
entidades externas desabilitadas primeiro.convertBodyTo em um corpo Source existente não é uma solução alternativa: essa conversão realiza uma transformação
de identidade através da mesma factory. A sondagem 5 no reprodutor é essa transformação de identidade, e ela vaza.com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl,
em vez de depender de TransformerFactory.newInstance(). A sondagem 6 é esse controle, e ele nega a leitura.Este repositório é publicado para fins educacionais e defensivos: para ajudar usuários do Apache Camel Quarkus a entender a vulnerabilidade, verificar se são afetados e confirmar que a atualização a resolve. Não use este material contra sistemas que você não possui ou opera.