You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Claus Ibsen (Jira)" <ji...@apache.org> on 2026/07/25 09:40:00 UTC
[jira] [Resolved] (CAMEL-24241) camel-ai-tool: AiToolExecutor skips the argument allowlist for tools declaring no parameters
[ https://issues.apache.org/jira/browse/CAMEL-24241?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Claus Ibsen resolved CAMEL-24241.
---------------------------------
Resolution: Fixed
Fixed via PR https://github.com/apache/camel/pull/25094
> 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)