TransformerFactory 导致 JAXP 外部访问限制失效针对 Apache Camel Quarkus 漏洞的可运行概念验证复现程序。在该漏洞中,XSLT 支持扩展(camel-quarkus-support-xalan)向 xslt 组件提供其自有的、由 Xalan 支持的 TransformerFactory,并将其注册为 JAXP 默认实现。Xalan-J 2.7.x 早于 JAXP 1.5,无法遵循 javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD 或 ACCESS_EXTERNAL_STYLESHEET —— 对这两者调用 setAttribute() 都会抛出 IllegalArgumentException —— 因此 Apache Camel 对其创建的 TransformerFactory 所施加的外部访问限制从未生效。
| 运行时 | 目录 | 技术栈 |
|---|---|---|
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.36.0(Quarkus 3.36.0,Camel 4.20.0) |
仅限 Camel Quarkus。 存在漏洞的代码是 Camel Quarkus 扩展,而非 Camel 组件。普通 Camel 和 Camel Spring Boot 使用 JDK 的
TransformerFactory,它遵循这两个属性,因此那里没有 可复现的内容 —— 本仓库因此没有camel-spring-boot/变体。
提供被转换 XML 文档的攻击者,可以通过该文档中的外部实体声明读取本地文件或访问内部网络位置。
cd camel-quarkus
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
在受影响的构建上的预期输出(节选 —— 驱动程序运行六个探测,参见
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: ...
也已针对 Camel Quarkus 3.40.0 验证:每个泄漏探测都归于沉寂,内部端点完全收不到请求,驱动程序打印 NOT reproduced。
在 xslt 组件路径上,只有已经以 javax.xml.transform.Source 形式到达转换器的消息体受影响。其他类型的消息体 —— String、byte[]、InputStream —— 会被 Apache Camel 转换为禁用了外部实体和外部 DTD 加载的 SAXSource,因此不受影响。复现程序中的探测 4 就是那条安全路径,与不安全路径并排展示。
由于该工厂还被注册为 JAXP 默认实现(该支持扩展附带 META-INF/services/javax.xml.transform.TransformerFactory),应用程序中任何其他通过 TransformerFactory.newInstance() 获取工厂的代码都会在无错误提示的情况下失去同样的限制。这就是为什么公告列出了那些自身从不进行任何转换的扩展:
| 扩展 | 暴露面 |
|---|---|
camel-quarkus-xslt | xslt 组件路径以及 JAXP 默认实现 |
camel-quarkus-xslt-saxon | JAXP 默认实现 |
camel-quarkus-tika | JAXP 默认实现 |
camel-quarkus-xmlsecurity | JAXP 默认实现 |
| 属性 | 值 |
|---|---|
| 组件 | camel-quarkus-support-xalan(XSLT 支持扩展) |
| CWE | CWE-611(XML 外部实体引用限制不当) |
| 严重性 | 高 |
| 攻击向量 | 在被转换的 XML 文档中声明外部实体或外部 DTD,且消息体已以 javax.xml.transform.Source 形式到达 xslt 端点 |
| 影响 | 读取本地文件;向内部网络位置发起请求(SSRF) |
| 受影响版本 | 从 3.2.0 起至 3.33.3 之前,从 3.34.0 起至 3.40.0 之前 |
| 修复版本 | 3.33.3(LTS 分支)、3.40.0 |
| GitHub issue | apache/camel-quarkus#9115 |
| 致谢 | 由内部使用 Claude Security Tool 分析发现 |
公告:https://camel.apache.org/security/CVE-2026-88789.html
XalanTransformerFactory 现在自行施加限制,而不再依赖 Xalan 无法遵循的属性:
XMLReader 进行解析 —— 这与 Apache Camel 的 XmlConverter.createSAXParserFactory() 用于 camel-xslt 自行转换为 SAXSource 的消息体时所用的配置相同。携带调用方配置的 XMLReader 的 SAXSource 按原样使用,而 DOMSource 和 StAXSource 已经完成解析。document() 函数获取的资源会被拒绝,除非应用程序自身的 URIResolver 能解析它们;该限制被安装到每一个提供转换对象的入口点上,包括那些 Xalan 不会将工厂解析器复制到其转换器上的 SAX 推送入口点。设置了自己解析器的应用程序 —— camel-xslt 在每次交换时都会这样做 —— 仍像以前一样覆盖它。已在 main 分支上修复,提交为
9a570b64 和
9dd11779,
并回溯移植到 3.33.x,提交为
ad9c5236 和
3d886769。
javax.xml.transform.Source 传入 xslt 端点。将消息体保留为 String、byte[] 或 InputStream,以便 Apache Camel 先将其转换为禁用了外部实体的 SAXSource。Source 消息体使用 convertBodyTo 不是变通方案:该转换会通过同一个工厂执行恒等转换。复现程序中的探测 5 就是那个恒等转换,它会泄漏。com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl,而不是依赖 TransformerFactory.newInstance()。探测 6 就是那个对照,它会拒绝读取。本仓库出于教育和防御目的发布:帮助 Apache Camel Quarkus 用户理解该漏洞、验证自己是否受影响,并确认升级可以解决该问题。请勿将本材料用于您不拥有或运营的系统。