
Runnable proof-of-concept reproducer for CVE-2026-78163 in Apache Camel camel-docling, demonstrating SSRF and local file disclosure via unvalidated String body input, with fixed-build control.
Runnable proof-of-concept reproducer for the Apache Camel vulnerability where DoclingProducer decided what a
String message body meant by inspecting its prefix:
http:// or https:// was handed to Docling as a remote URL to fetch (SSRF), and/ (or containing a backslash) was read from the local filesystem (file disclosure).The mode was chosen implicitly, with no endpoint option to pin a single interpretation, and — unlike the Camel
header namespace — the message body is never filtered by a HeaderFilterStrategy. So a route that means
"convert whatever text arrives in the body" silently became a fetcher of remote resources or a reader of local
files whenever the attacker-controlled text began with one of those prefixes.
| Runtime | Directory | Stack | Shows |
|---|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-docling 4.22.0 (affected; fixed 4.22.1) | SSRF and file disclosure, plus the fixed-build control |
| Camel Quarkus | camel-quarkus/ | Quarkus 3.29.0 + camel-quarkus-docling 3.29.0 (Camel 4.15.0, affected) | file disclosure only (see note) |
Version coverage. The local file-disclosure sink has existed since camel-docling was introduced in 4.15.0; the remote-URL sink was added in 4.16.0 with docling-serve support. The latest Camel Quarkus (3.29.0) bundles Camel 4.15.0, so its module demonstrates the file disclosure only. The fix ships in Camel 4.18.5 / 4.22.1 / 4.23.0; the Spring Boot module runs both the affected build (4.22.0) and the fixed build (4.22.1), so it also demonstrates the patched behaviour. No released Camel Quarkus yet bundles a fixed Camel.
Neither reproducer needs a real Docling install: a tiny fake docling CLI (fake-docling/docling) stands in for
the binary and makes visible what the real one would do with the producer-supplied input — fetch a URL, or read a
file. It is benign: it only echoes what it was told to process and logs its own invocation. The point of the CVE is
that an attacker-supplied body reaches that argument at all, with no opt-in.
The Spring Boot app also runs an internal-only HTTP endpoint on 127.0.0.1:9099 (only port 8080 is published,
so an external client cannot reach 9099 directly) and a local secret file. The attacker sends only text:
http://127.0.0.1:9099/internal-secret → the server-side docling invocation fetches the
internal endpoint and its secret is returned to the caller./tmp/cve-2026-78163-secret.txt → the local file is read and returned.On the affected build both succeed; on the fixed build both are rejected with an IllegalArgumentException
naming the option (allowUrlSource / allowFilePathSource) that would be required to enable them, and docling is
never invoked.
cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
Expected output on the affected Spring Boot build:
[1] SSRF — sending body = http://127.0.0.1:9099/internal-secret
>>> PROVEN SSRF: the server-side docling invocation fetched the attacker-controlled internal URL.
>>> internal victim saw: [GET /internal-secret]
>>> content returned to the caller:
| INTERNAL-SECRET-DATA (only reachable from inside the deployment)
[2] File disclosure — sending body = /tmp/cve-2026-78163-secret.txt
>>> PROVEN file disclosure: the attacker-named local file was read and returned.
| TOP-SECRET-FILE-CONTENT (local file an attacker should not be able to read)
| Property | Value |
|---|---|
| Component | camel-docling (camel-docling-starter / camel-quarkus-docling) |
| CWE | CWE-918 (SSRF), CWE-22 (Path Traversal), CWE-200 (Information Exposure) |
| Severity | MEDIUM |
| Attack vector | A String message body forwarded into a docling endpoint, whose prefix selects a URL-fetch or file-read sink; the body is not subject to HeaderFilterStrategy |
| Impact | Server-side fetch of attacker-chosen URLs (internal services) and disclosure of local files |
| Affected Versions | From 4.15.0 before 4.18.5, from 4.19.0 before 4.22.1 (file disclosure since 4.15.0; URL sink since 4.16.0) |
| Fixed Versions | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24422 |
| Credit | Li Zhiyao (BUPT) |
Advisory: https://camel.apache.org/security/CVE-2026-78163.html
A String body is now treated as the document itself by default. The two location readings became opt-in through
new endpoint options allowUrlSource and allowFilePathSource (both default false); a body that looks like a URL
or path is otherwise rejected with an IllegalArgumentException naming the option that would enable it. A further
inputBaseDirectory option confines local input paths to a configured directory. Typed bodies (File, byte[],
InputStream) and the CamelDoclingInputFilePath header already state their meaning and are not gated (but remain
subject to inputBaseDirectory).
Do not route externally originated message bodies into a docling endpoint; pass the document through a typed body
(File, byte[], InputStream) or the CamelDoclingInputFilePath header so the body is never subject to prefix
interpretation.
This repository is published for educational and defensive purposes: to help Apache Camel users understand the
vulnerability, verify whether they are affected, and confirm that upgrading resolves it. The fake docling CLI and
the "secrets" are inert local fixtures. Do not use this material against systems you do not own or operate.