[ 
https://issues.apache.org/jira/browse/CAMEL-24241?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen updated CAMEL-24241:
--------------------------------
    Fix Version/s: 4.22.0

> 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
>            Priority: Major
>             Fix For: 4.22.0
>
>
> 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