gnodet-bot commented on code in PR #28295:
URL: https://github.com/apache/camel/pull/28295#discussion_r4348719897


##########
components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolExecutor.java:
##########
@@ -131,20 +149,26 @@ public static AiToolResult execute(AiToolSpec spec, 
Map<String, Object> argument
         // Set each argument as an exchange header so route expressions 
(${header.city})
         // and SQL bindings work naturally. Filter out Camel-internal names to 
prevent
         // header-namespace injection (CVE-2025-27636 family).
-        for (Map.Entry<String, Object> entry : argsCopy.entrySet()) {
-            String name = entry.getKey();
+        bodyArguments.keySet().removeIf(name -> {
             String lower = name.toLowerCase(Locale.ROOT);
             if (lower.startsWith("camel") || 
lower.startsWith("org.apache.camel.")) {
                 LOG.warn("Rejecting tool argument '{}' for tool '{}' -- 
argument names starting with "
                          + "'Camel' or 'org.apache.camel.' are reserved for 
internal use",
                         name, toolName);
-                continue;
+                return true;
             }
-            exchange.getMessage().setHeader(name, entry.getValue());
-        }
+            return false;
+        });
+        argsCopy.keySet().retainAll(bodyArguments.keySet());

Review Comment:
   ⚠️ **Potential silent loss of required arguments**
   
   The execution flow is:
   1. `argsCopy` = defensive copy of `arguments`
   2. `bodyArguments = new HashMap<>(argsCopy)` — same keys initially
   3. Undeclared keys filtered from `argsCopy` (required+declared params 
survive)
   4. Required-argument check runs against `argsCopy` ✅ — declared required 
param passes
   5. `bodyArguments.keySet().removeIf(name -> lower.startsWith("camel") || 
...)` — strips anything with a `camel`-prefixed name
   6. **`argsCopy.keySet().retainAll(bodyArguments.keySet())`** — syncs 
`argsCopy` down to `bodyArguments`
   
   If a tool parameter is declared (survives step 3), required (passes step 4), 
*and* its name starts with `"camel"` (case-insensitive) — e.g. `"camelCase"`, 
`"camelHump"` — it passes validation but is silently removed from both 
`argsCopy` (headers) and `bodyArguments` (body) before the route executes. The 
route receives neither the header nor the body argument.
   
   This is unlikely in practice since users rarely choose parameter names that 
collide with the Camel reserved namespace, but it's a logical gap worth 
documenting or guarding against. One option: run the camel-prefix strip on both 
`bodyArguments` **and** `argsCopy` before the required-argument check, so 
validation and stripping share the same view of the argument set.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to