Andrea Cosentino created CAMEL-24241:
----------------------------------------

             Summary: camel-ai-tool: AiToolExecutor skips the argument 
allowlist for tools declaring no parameters
                 Key: CAMEL-24241
                 URL: https://issues.apache.org/jira/browse/CAMEL-24241
             Project: Camel
          Issue Type: Bug
            Reporter: Andrea Cosentino
            Assignee: Andrea Cosentino


CAMEL-23382 ({{bfd60dfb361e}}) moved the LLM-tool-argument handling out of 
{{LangChain4jAgentProducer}} into the new shared {{AiToolExecutor}}. In the 
process, the argument allowlist regained a bypass that CAMEL-23621 had 
deliberately removed.

h3. Current code

{{components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolExecutor.java}}:

{noformat}
if (!argsCopy.isEmpty() && !spec.getParameterDefs().isEmpty()) {
    Set<String> declaredParams = spec.getParameterDefs().keySet();
    argsCopy.keySet().removeIf(name -> {
        if (!declaredParams.contains(name)) { ...filter... }
    });
}
{noformat}

When {{spec.getParameterDefs()}} is empty, the whole filtering block is 
skipped. The loop that follows then sets every remaining argument as an 
exchange header.

A tool that declares no parameters is entirely legal — a {{description}} alone 
is sufficient. For such a tool, the LLM can therefore cause arbitrary header 
names (of its choosing) to be set on the exchange that runs the tool route.

h3. Why this is a regression

Commit {{e9c4541a91ce}}, titled "CAMEL-23621: remove backwards-compatibility 
bypass and fix raw JsonNode headers", removed exactly this pattern from three 
places:

{noformat}
-    if (!allowedParams.isEmpty() && !allowedParams.contains(name)) {
+    if (!allowedParams.contains(name)) {
{noformat}

(in {{LangChain4jAgentProducer}}, {{LangChain4jToolsProducer}} and 
{{SpringAiToolsEndpoint}}).

The two producers still have the strict form today. Only the new shared 
executor reintroduced the {{isEmpty()}} guard.

h3. Severity — hardening, not a CVE

{{AiToolExecutor}} does keep a case-insensitive rejection of names starting 
with {{camel}} or {{org.apache.camel.}}, so the CVE-2025-27636 header-injection 
family is *not* reachable through this path. What is unfiltered is arbitrary 
*non-Camel* header names originating from model output.

That still matters: LLM output is attacker-influenceable through prompt 
injection, and tool routes commonly forward headers to downstream components 
(HTTP producers, SQL named parameters, etc.). The route author's declared 
parameter set is the intended contract, and for zero-parameter tools it is 
currently not enforced.

h3. Suggested fix

Drop the {{&& !spec.getParameterDefs().isEmpty()}} condition so an empty 
declaration means "no arguments are allowed" rather than "all arguments are 
allowed" — matching what CAMEL-23621 established for the sibling producers:

{noformat}
if (!argsCopy.isEmpty()) {
    Set<String> declaredParams = spec.getParameterDefs().keySet();
    ...
}
{noformat}

A test covering a zero-parameter tool that receives unexpected arguments would 
lock the behaviour in; the existing tests appear to cover only tools that 
declare parameters.

h3. Related

Found while reviewing PR #24992 (CAMEL-23944). Not caused by that PR — it 
patches the pre-CAMEL-23382 code and is unrelated.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to