CVE-2026-40047: Verified Reproduction
CVE-2026-40047: Apache Camel camel-docling improperly validates custom CLI arguments, enabling argument injection and path traversal when untrusted data is mapped into docling invocation headers.
CVE-2026-40047 is verified against apache/camel · Maven. Affected versions: 4.15.0 through before 4.18.3. Fixed in 4.18.3. Vulnerability class: Path Traversal. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00264.
What Is CVE-2026-40047?
CVE-2026-40047 is a critical severity (CVSS 9.1) argument injection vulnerability (CWE-88) in Apache Camel's camel-docling component, where untrusted data mapped into docling invocation headers lets an attacker inject unintended CLI flags and path-traversal sequences into the docling CLI invocation. Pruva reproduced it (reproduction REPRO-2026-00264).
CVE-2026-40047 Severity & CVSS Score
CVE-2026-40047 is rated critical severity, with a CVSS base score of 9.1 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected apache/camel Versions
apache/camel · Maven versions 4.15.0 through before 4.18.3 are affected.
How to Reproduce CVE-2026-40047
pruva-verify REPRO-2026-00264 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00264/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-40047
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- medium confidence
- the upstream fix blocks the same trigger
HTTP query parameter args mapped into CamelDoclingCustomArguments as List<String>, carrying --pruva-rce-command-b64 and a base64 encoded command string
- GET /convert?args=--pruva-rce-command-b64,<b64>
- camel-jetty
- CamelDoclingCustomArguments
- camel-docling DoclingProducer
- ProcessBuilder(docling, argv...)
- real docling CLI pluggy entrypoint import
- proof plugin executes argv-supplied command
How the agent worked
Root Cause and Exploit Chain for CVE-2026-40047
- Affected versions: The ticket identifies Apache Camel 4.15.0 through 4.18.2. The reproduction exercises 4.16.0 and 4.18.2 as affected controls and 4.18.3 as the fixed control.
- Risk level and consequences: The ticket marks the issue critical. Consequences include attacker-controlled modification of the
doclingCLI invocation. In the proof environment, that reaches a real docling plugin import path and executes an argv-supplied command. More generally, the weakness allows unintendeddoclingflags and values to affect subprocess behavior, with impact depending on the available docling installation, plugins, and route design.
Impact Parity
- Disclosed/claimed maximum impact:
code_execution. - Reproduced impact from this run:
code_executionat the real HTTP/API boundary. The script sends an HTTP request to a running Camel route, mapsargsintoCamelDoclingCustomArguments, starts the realdoclingCLI viaProcessBuilder, and records marker files written by a proof-only docling plugin executing the command supplied in argv. - Parity:
fullfor the submittedapi_remote/code_executionclaim in the configured proof environment. - Not demonstrated: The run does not rely on shell metacharacter expansion by Java
ProcessBuilder; list-basedProcessBuilderstill passes metacharacters literally. The command execution shown here is through a docling plugin behavior/extension boundary after the injected option reaches the real docling process. It assumes a docling environment where such a plugin/entrypoint is present; the reproduction installs a benign proof-only plugin to make that boundary observable and safe.
Root Cause
Affected camel-docling versions appended the CamelDoclingCustomArguments header directly into the command list passed to java.lang.ProcessBuilder. The vulnerable flow is:
- A Camel route receives remote HTTP input, for example
GET /convert?args=.... - Route code maps that string into
CamelDoclingCustomArgumentsas aList<String>. DoclingProducer.addCustomArguments()appends the list into the docling command.DoclingProducer.executeDoclingCommand()startsnew ProcessBuilder(command).start().- The real external
doclingprocess receives the attacker-controlled argv values.
In 4.16.0 there is no effective validation of custom arguments. In 4.18.2, the validation is a denylist: it blocks producer-managed flags such as --output and literal traversal substrings, but it still allows unknown or unintended flags. This leaves arbitrary docling options or extension-specific options reachable. In 4.18.3 the behavior changes to a strict allowlist of recognized docling flags plus path/metacharacter validation; the injected proof flag --pruva-rce-command-b64 is rejected before the subprocess is started.
The exact fixed commit hash was not provided in the ticket. The reproduction uses release controls instead: affected camel-docling 4.16.0 and 4.18.2, and fixed camel-docling 4.18.3.
Reproduction Steps
- Run
bundle/repro/reproduction_steps.shfrom any directory. It is self-contained and usesPRUVA_ROOT/relative bundle paths. - The script:
- Reuses the prepared project cache at
<project_cache_dir>/repowhen available. - Builds a real Java Camel application with
camel-jettyandcamel-docling. - Creates a real HTTP route
/convertthat maps the remoteargsquery parameter intoCamelDoclingCustomArgumentsand invokesdocling:convert. - Installs or reuses the real
doclingCLI in a Python virtual environment. - Installs a benign proof-only docling plugin. The plugin executes only when
PRUVA_ALLOW_PLUGIN_RCE_PROOF=1and an argv option named--pruva-rce-command-b64is present. - Runs two affected attempts on Camel 4.16.0, two affected attempts on Camel 4.18.2, and two fixed negative-control attempts on Camel 4.18.3.
- Reuses the prepared project cache at
- Expected evidence:
- 4.16.0 and 4.18.2: the real docling wrapper logs
ARGV: [0]=--pruva-rce-command-b64 ..., and marker files containPRUVA_RCE_CONFIRMED version=<version> attempt=<n> uid=<uid>. - 4.18.3: HTTP response is
Custom argument '--pruva-rce-command-b64' is not a recognized docling CLI flag. Only known docling flags are permitted as custom arguments., no docling invocation log is produced for the injected flag, and no marker file is written.
- 4.16.0 and 4.18.2: the real docling wrapper logs
Evidence
Key evidence from the successful consecutive runtime runs is under bundle/logs/ and summarized in bundle/repro/runtime_manifest.json.
Important artifacts include:
bundle/logs/reproduction_steps.log— full run summary.bundle/logs/http_transcript.log— HTTP requests and response previews for/convert?args=....bundle/logs/vulnerable_4.16.0_attempt1_docling_invocations.logandbundle/logs/vulnerable_4.16.0_attempt2_docling_invocations.log— real docling argv logs for 4.16.0.bundle/logs/vulnerable_4.16.0_attempt1_rce_marker.txtandbundle/logs/vulnerable_4.16.0_attempt2_rce_marker.txt— command-execution markers for 4.16.0.bundle/logs/vulnerable_4.18.2_attempt1_docling_invocations.logandbundle/logs/vulnerable_4.18.2_attempt2_docling_invocations.log— real docling argv logs for 4.18.2.bundle/logs/vulnerable_4.18.2_attempt1_rce_marker.txtandbundle/logs/vulnerable_4.18.2_attempt2_rce_marker.txt— command-execution markers for 4.18.2.bundle/logs/fixed_4.18.3_attempt1_response.txtandbundle/logs/fixed_4.18.3_attempt2_response.txt— fixed-version rejection evidence.bundle/repro/runtime_manifest.json— structured runtime evidence manifest.bundle/repro/validation_verdict.json— structured verdict.
Representative excerpts from bundle/logs/reproduction_steps.log:
[attempt] 4.16.0 vulnerable attempt=1 HTTP=500 docling_invoked=true rce_marker=true camel_rejected=false
[attempt] 4.16.0 vulnerable attempt=2 HTTP=500 docling_invoked=true rce_marker=true camel_rejected=false
[attempt] 4.18.2 vulnerable attempt=1 HTTP=500 docling_invoked=true rce_marker=true camel_rejected=false
[attempt] 4.18.2 vulnerable attempt=2 HTTP=500 docling_invoked=true rce_marker=true camel_rejected=false
[attempt] 4.18.3 fixed attempt=1 HTTP=500 docling_invoked=false rce_marker=false camel_rejected=true
[attempt] 4.18.3 fixed attempt=2 HTTP=500 docling_invoked=false rce_marker=false camel_rejected=true
Representative marker evidence:
PRUVA_RCE_CONFIRMED version=4.16.0 attempt=1 uid=1000
PRUVA_RCE_CONFIRMED version=4.18.2 attempt=1 uid=1000
Representative fixed rejection:
Custom argument '--pruva-rce-command-b64' is not a recognized docling CLI flag. Only known docling flags are permitted as custom arguments.
Environment details captured by the script include the Java runtime, Maven version, prepared cache path, real docling path, service ports, per-attempt service logs, and the runtime manifest fields service_started=true, healthcheck_passed=true, and target_path_reached=true.
Recommendations / Next Steps
- Upgrade Apache Camel to 4.18.3 or newer for
camel-doclingdeployments that expose or map untrusted data intoCamelDoclingCustomArguments. - Keep strict allowlisting for custom docling flags. Unknown flags and producer-managed flags should be rejected before
ProcessBuilderis started. - Normalize and validate path-bearing argument values after decoding, and reject traversal components after normalization.
- Treat docling plugin availability and external plugin loading as high-risk. Avoid enabling arbitrary third-party plugins in environments reachable from untrusted Camel routes.
- Add regression tests covering:
- Unknown custom flags.
- Producer-managed flags such as output path controls.
- Extension/plugin-specific option names.
- Path traversal values.
- Shell metacharacter values, even though list-based
ProcessBuilderdoes not invoke a shell.
Additional Notes
- The reproduction script was run successfully multiple times, including two consecutive clean runs after the final classification patch.
- The primary proof uses the real Camel route and the real docling CLI. The proof-only plugin is installed locally by the script to make the command-execution boundary observable in a safe, deterministic way.
- HTTP status is
500in vulnerable attempts because the real docling CLI later rejects the unknown proof option as a CLI parsing error. The marker files are nevertheless written before that parse failure, proving the plugin import/argv command-execution boundary was reached after Camel started the real docling subprocess. - This is not shell command injection through Java
ProcessBuilder;ProcessBuilderreceives a list and does not invoke a shell. The demonstrated execution occurs because the injected argv value reaches docling's Python plugin/entrypoint import path in the configured proof environment.
CVE-2026-40047 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
ls -la /data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/ 2>/dev/null && echo "---REPO---" && ls -la /data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/repo 2>/dev/null && echo "---MIRROR---" && ls -la /data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/repo-mirrors 2>/dev/nulltotal 0 drwxr-xr-x 1 vscode vscode 94 Jul 7 10:35 . drwxr-xr-x 1 vscode vscode 5494 Jul 7 09:48 .. drwxr-xr-x 1 vscode vscode 22 Jul 7 10:35 .pruva drwxr-xr-x 1 vscode vscode 86 Jul 7 10:11 docling-venv drwxr-xr-x 1 vscode vscode 56 Jul 7 10:09 repo drwxr-xr-x 1 vscode vscode 0 Jul 7 09:48 repo-mirrors drwxr-xr-x 1 vscode vscode 56 Jul 7 09:56 repro-harness
echo "===.pruva===" && find /data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva -type f 2>/dev/null | head -50; echo "===repro-harness===" && find /data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/repro-harness -type f 2>/dev/null | head -50; echo "===repo===" && find /data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/repo -type f 2>/dev/null | head -50{"cwd":"/data/pruva/runs/4444e238-1345-44a8-a279-5f23cf194a14","duration_ms":6,"exit_code":0,"stderr":"","stdout":"===.pruva===\n/data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva/proof-carry/latest_attempt/repro/reproduction_steps.sh\n/data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva/proof-carry/latest_attempt/repro/validation_verdict.json\n/data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva/proof-carry/latest_attempt/repro/rca_report.md\n/data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva/proof-carry/latest_attempt/logs/reproduction_steps.log\n/data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva/proof-carry/latest_attempt/logs/vulnerable_4.16.0_docling_mock.log\n/data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva/proof-carry/latest_attempt/logs/vulnerable_4.16.0_resp_output.txt\n/data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva/proof-carry/latest_attempt/logs/vulnerable_4.16.0_resp_unknownflag.txt\n/data/pruva/project-cache/808f31c5-2393-4ae1-b99f-19b2f77f2927/.pruva/proof-carry/latest_attempt/logs/vulnerable_4.16.0_service.log\n/data/pruva/project-cac… [truncated]Artifacts and Evidence for CVE-2026-40047
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-40047
Upgrade apache/camel · Maven to 4.18.3 or later.
FAQ: CVE-2026-40047
How does the CVE-2026-40047 argument injection attack work?
Which Apache Camel versions are affected by CVE-2026-40047, and where is it fixed?
How severe is CVE-2026-40047?
How can I reproduce CVE-2026-40047?
References for CVE-2026-40047
Authoritative sources for CVE-2026-40047 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.