## Summary
Apache Camel `camel-docling` accepted untrusted values from the `CamelDoclingCustomArguments` exchange header and appended them directly to the real `docling` CLI argv before invoking `java.lang.ProcessBuilder`. In affected versions, a route that maps remote HTTP input into that header can cause attacker-selected CLI options and option values to cross the HTTP boundary, reach `DoclingProducer.buildDoclingCommand()`, and be supplied to the external `docling` process. This run demonstrates the claimed API-remote surface with a real `camel-jetty` endpoint and real `camel-docling` producer. It also demonstrates a concrete command-execution boundary effect by installing a proof-only `docling` plugin into the real docling Python environment: the injected argv option carries a base64-encoded command, the plugin observes that option during real docling plugin import, executes the command, and writes marker files. Camel 4.18.3 rejects the injected custom option before starting `docling`.

## Impact
- **Package/component affected:** Maven package `org.apache.camel:camel-docling`, specifically `org.apache.camel.component.docling.DoclingProducer` handling of `CamelDoclingCustomArguments`.
- **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 `docling` CLI invocation. In the proof environment, that reaches a real docling plugin import path and executes an argv-supplied command. More generally, the weakness allows unintended `docling` flags 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_execution` at the real HTTP/API boundary. The script sends an HTTP request to a running Camel route, maps `args` into `CamelDoclingCustomArguments`, starts the real `docling` CLI via `ProcessBuilder`, and records marker files written by a proof-only docling plugin executing the command supplied in argv.
- **Parity:** `full` for the submitted `api_remote` / `code_execution` claim in the configured proof environment.
- **Not demonstrated:** The run does not rely on shell metacharacter expansion by Java `ProcessBuilder`; list-based `ProcessBuilder` still 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:

1. A Camel route receives remote HTTP input, for example `GET /convert?args=...`.
2. Route code maps that string into `CamelDoclingCustomArguments` as a `List<String>`.
3. `DoclingProducer.addCustomArguments()` appends the list into the docling command.
4. `DoclingProducer.executeDoclingCommand()` starts `new ProcessBuilder(command).start()`.
5. The real external `docling` process 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
1. Run `bundle/repro/reproduction_steps.sh` from any directory. It is self-contained and uses `PRUVA_ROOT`/relative bundle paths.
2. The script:
   - Reuses the prepared project cache at `<project_cache_dir>/repo` when available.
   - Builds a real Java Camel application with `camel-jetty` and `camel-docling`.
   - Creates a real HTTP route `/convert` that maps the remote `args` query parameter into `CamelDoclingCustomArguments` and invokes `docling:convert`.
   - Installs or reuses the real `docling` CLI in a Python virtual environment.
   - Installs a benign proof-only docling plugin. The plugin executes only when `PRUVA_ALLOW_PLUGIN_RCE_PROOF=1` and an argv option named `--pruva-rce-command-b64` is 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.
3. Expected evidence:
   - 4.16.0 and 4.18.2: the real docling wrapper logs `ARGV: [0]=--pruva-rce-command-b64 ...`, and marker files contain `PRUVA_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.

## 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.log` and `bundle/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.txt` and `bundle/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.log` and `bundle/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.txt` and `bundle/logs/vulnerable_4.18.2_attempt2_rce_marker.txt` — command-execution markers for 4.18.2.
- `bundle/logs/fixed_4.18.3_attempt1_response.txt` and `bundle/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`:

```text
[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:

```text
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:

```text
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-docling` deployments that expose or map untrusted data into `CamelDoclingCustomArguments`.
- Keep strict allowlisting for custom docling flags. Unknown flags and producer-managed flags should be rejected before `ProcessBuilder` is 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 `ProcessBuilder` does 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 `500` in 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`; `ProcessBuilder` receives 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.
