
Prova de conceito executável que reproduz a CVE-2026-95629, uma falha de path traversal no Apache Camel camel-docling, em que o cabeçalho output-path chega ao parâmetro --output do docling sem qualquer tratamento.
--output literalmenteReprodutor de prova de conceito executável para a vulnerabilidade do Apache Camel em que o DoclingProducer, ao executar
a ferramenta externa docling em modo CLI (o padrão), entregava o valor do
cabeçalho CamelDoclingOutputFilePath à flag --output do docling literalmente: sem normalização, um caminho
absoluto ou um caminho contendo segmentos .. era aceito como fornecido, e nenhuma opção de endpoint conseguia restringi-lo.
| Runtime | Diretório | Stack |
|---|---|---|
| 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) |
O Docling grava o resultado da conversão — Markdown, HTML, JSON ou texto — nesse diretório, nomeando o arquivo com base no arquivo de entrada, e o producer em seguida remove apenas seu próprio diretório temporário, de modo que o arquivo permanece no local. Um agente capaz de definir o cabeçalho poderia, portanto, fazer com que a saída da conversão fosse criada em qualquer diretório no qual o processo Camel tenha permissão de escrita.
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
Saída em um build afetado (idêntica em ambos os runtimes):
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: ...
A sonda 4 é a forma do problema. A validação de argumentos personalizados adicionada pela correção para
CVE-2026-40047 recusa --output e -o em
CamelDoclingCustomArguments e diz aos chamadores para escolher o diretório de saída com este cabeçalho em vez disso —
assim, o único valor que decide onde o docling escreve era o único valor que chegava à linha de comando sem nenhuma das
verificações aplicadas aos argumentos personalizados.
A troca em si falha após as sondas 2 e 3 ("falhou depois"), porque o produtor então procura a saída convertida no seu próprio diretório temporário e não a encontra lá. Isso é cosmético: a escrita já aconteceu, que é o que a listagem de ficheiros no final mostra.
Não é necessária nenhuma instalação do docling. A opção doclingCommand do endpoint aponta para um substituto de gravação para
a CLI, que tanto regista o vetor de argumentos que recebeu como escreve um ficheiro no que quer que --output
tenha nomeado, tal como o docling faz. O DoclingProducer real e o addOutputDirectoryArguments() real são executados.
Apenas o modo CLI usa este cabeçalho; o modo docling-serve não o usa.
CamelDoclingOutputFilePath pertence ao namespace de cabeçalhos do Camel, que os consumidores que aplicam a
filtragem de cabeçalhos predefinida do Camel — os consumidores JMS e Kafka, por exemplo — removem das mensagens recebidas. O
problema é alcançado quando uma rota encaminha valores influenciados externamente para o cabeçalho, ou quando um consumidor
mapeia cabeçalhos recebidos sem essa filtragem.
O conteúdo do ficheiro escrito é a conversão do documento transportado pela mensagem, pelo que é moldado por quem fornece esse documento sem ser escrito byte a byte; quando o documento chega no corpo da mensagem, o produtor armazena-o sob um nome temporário aleatório, que o ficheiro de saída então transporta.
| Propriedade | Valor |
|---|---|
| Componente | camel-docling (DoclingProducer.addOutputDirectoryArguments()) |
| CWE | CWE-22 (Limitação Imprópria de um Caminho para um Diretório Restrito) |
| Severidade | Média |
| Vetor de ataque | Um diretório absoluto ou contendo .. no cabeçalho CamelDoclingOutputFilePath |
| Impacto | Saída de conversão criada em qualquer diretório onde o processo Camel possa escrever |
| Versões Afetadas | Da 4.15.0 antes da 4.18.5, da 4.19.0 antes da 4.22.2 |
| Versões Corrigidas | 4.18.5, 4.22.2, 4.23.0 |
| JIRA | CAMEL-24894 |
| Crédito | Zhixi "Jace" Sun, investigador de segurança independente |
Aviso: https://camel.apache.org/security/CVE-2026-95629.html
Problema irmão no mesmo componente, mesma vaga de lançamento: CVE-2026-95628 (caminhos absolutos aceites como valores de argumentos personalizados).
O cabeçalho agora recebe a mesma normalização e contenção opcional ao diretório base que os caminhos de entrada, através de
resolveWithinOutputBaseDirectory(). Mas a opção de endpoint outputBaseDirectory que a correção adiciona está
não definida por predefinição, e a sua própria documentação diz que, quando vazia, nenhuma restrição de diretório é aplicada
e o valor do cabeçalho é apenas normalizado.
Verificado contra 4.22.1 → 4.22.2, com outputBaseDirectory deixado por definir:
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.
O driver reporta esse estado separadamente em vez de chamá-lo de corrigido, porque é o estado em que a
maioria das implantações ficará logo após uma atualização. Após a atualização, defina outputBaseDirectory em todo
endpoint docling cujo cabeçalho possa carregar um valor influenciado externamente.
Corrigido em main em apache/camel#26737 (48485d40), com backport
para camel-4.22.x em #27365 e para camel-4.18.x em
#27362.