This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 5ab43431e22b CAMEL-24295: anchor the security-scan option match on a
token boundary, and mark the Simple nested option (#27117)
5ab43431e22b is described below
commit 5ab43431e22bb68e329c2180913f217fcbe56b2e
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Oct 2 16:19:26 2026 +0200
CAMEL-24295: anchor the security-scan option match on a token boundary, and
mark the Simple nested option (#27117)
Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
.../org/apache/camel/catalog/languages/file.json | 2 +-
.../org/apache/camel/catalog/languages/simple.json | 2 +-
.../org/apache/camel/catalog/models/simple.json | 2 +-
.../camel/catalog/schemas/camelYamlDsl-model.json | 4 +-
.../org/apache/camel/language/simple/file.json | 2 +-
.../org/apache/camel/language/simple/simple.json | 2 +-
.../org/apache/camel/model/language/simple.json | 2 +-
.../camel/model/language/SimpleExpression.java | 3 +-
.../java/org/apache/camel/util/SecurityUtils.java | 27 ++++++++++-
.../org/apache/camel/util/SecurityUtilsTest.java | 33 ++++++++++++++
.../jbang/core/commands/mcp/SecurityScanTools.java | 6 +++
.../core/commands/mcp/SecurityScanToolsTest.java | 53 ++++++++++++++++++++++
.../resources/schema/camelYamlDsl-model.json | 4 +-
13 files changed, 130 insertions(+), 12 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/file.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/file.json
index 90523bcc10d2..f247bf77992d 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/file.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/file.json
@@ -20,7 +20,7 @@
"expression": { "index": 1, "kind": "value", "displayName": "Expression",
"group": "common", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The expression value in your chosen language syntax." },
"trimResult": { "index": 2, "kind": "attribute", "displayName": "Trim
Result", "group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to trim the returned values when
this language is in use." },
"pretty": { "index": 3, "kind": "attribute", "displayName": "Pretty",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "To pretty format the output (only JSon
or XML supported)." },
- "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If the result is a
nested simple expression should this expression be evaluated as well." },
+ "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "security", "label": "advanced,security", "required": false, "type":
"boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired":
false, "secret": false, "security": "insecure:dev", "defaultValue": false,
"description": "If the result is a nested simple expression should this
expression be evaluated as well." },
"resultType": { "index": 5, "kind": "attribute", "displayName": "Result
Type", "group": "common", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The class of the result type (type from output)." },
"trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "group":
"advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": true, "description": "Whether to trim the
source code to remove leading and trailing whitespaces and line breaks." },
"resolveResource": { "index": 7, "kind": "attribute", "displayName":
"Resolve Resource", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether a result of the expression that is a String starting with resource: is
loaded as a resource and its content becomes the result, e.g. a script that
returns resource:file:order.json o [...]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
index d3c1a3ef82db..d7286003a364 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
@@ -20,7 +20,7 @@
"expression": { "index": 1, "kind": "value", "displayName": "Expression",
"group": "common", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The expression value in your chosen language syntax." },
"trimResult": { "index": 2, "kind": "attribute", "displayName": "Trim
Result", "group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to trim the returned values when
this language is in use." },
"pretty": { "index": 3, "kind": "attribute", "displayName": "Pretty",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "To pretty format the output (only JSon
or XML supported)." },
- "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If the result is a
nested simple expression should this expression be evaluated as well." },
+ "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "security", "label": "advanced,security", "required": false, "type":
"boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired":
false, "secret": false, "security": "insecure:dev", "defaultValue": false,
"description": "If the result is a nested simple expression should this
expression be evaluated as well." },
"resultType": { "index": 5, "kind": "attribute", "displayName": "Result
Type", "group": "common", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The class of the result type (type from output)." },
"trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "group":
"advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": true, "description": "Whether to trim the
source code to remove leading and trailing whitespaces and line breaks." },
"resolveResource": { "index": 7, "kind": "attribute", "displayName":
"Resolve Resource", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether a result of the expression that is a String starting with resource: is
loaded as a resource and its content becomes the result, e.g. a script that
returns resource:file:order.json o [...]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/simple.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/simple.json
index 16ae4e0aa725..54a83ef0c577 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/simple.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/simple.json
@@ -17,7 +17,7 @@
"expression": { "index": 1, "kind": "value", "displayName": "Expression",
"group": "common", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The expression value in your chosen language syntax." },
"trimResult": { "index": 2, "kind": "attribute", "displayName": "Trim
Result", "group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to trim the returned values when
this language is in use." },
"pretty": { "index": 3, "kind": "attribute", "displayName": "Pretty",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "To pretty format the output (only JSon
or XML supported)." },
- "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If the result is a
nested simple expression should this expression be evaluated as well." },
+ "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "security", "label": "advanced,security", "required": false, "type":
"boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired":
false, "secret": false, "security": "insecure:dev", "defaultValue": false,
"description": "If the result is a nested simple expression should this
expression be evaluated as well." },
"resultType": { "index": 5, "kind": "attribute", "displayName": "Result
Type", "group": "common", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The class of the result type (type from output)." },
"trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "group":
"advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": true, "description": "Whether to trim the
source code to remove leading and trailing whitespaces and line breaks." },
"resolveResource": { "index": 7, "kind": "attribute", "displayName":
"Resolve Resource", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether a result of the expression that is a String starting with resource: is
loaded as a resource and its content becomes the result, e.g. a script that
returns resource:file:order.json o [...]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
index 6c97b9d7b50c..3b2a2b3e4daf 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
@@ -16118,8 +16118,8 @@
"displayName" : "Nested",
"kind" : "attribute",
"index" : 4,
- "group" : "advanced",
- "label" : "advanced"
+ "group" : "security",
+ "label" : "advanced,security"
}, {
"name" : "resultType",
"type" : "string",
diff --git
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/file.json
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/file.json
index 90523bcc10d2..f247bf77992d 100644
---
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/file.json
+++
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/file.json
@@ -20,7 +20,7 @@
"expression": { "index": 1, "kind": "value", "displayName": "Expression",
"group": "common", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The expression value in your chosen language syntax." },
"trimResult": { "index": 2, "kind": "attribute", "displayName": "Trim
Result", "group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to trim the returned values when
this language is in use." },
"pretty": { "index": 3, "kind": "attribute", "displayName": "Pretty",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "To pretty format the output (only JSon
or XML supported)." },
- "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If the result is a
nested simple expression should this expression be evaluated as well." },
+ "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "security", "label": "advanced,security", "required": false, "type":
"boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired":
false, "secret": false, "security": "insecure:dev", "defaultValue": false,
"description": "If the result is a nested simple expression should this
expression be evaluated as well." },
"resultType": { "index": 5, "kind": "attribute", "displayName": "Result
Type", "group": "common", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The class of the result type (type from output)." },
"trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "group":
"advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": true, "description": "Whether to trim the
source code to remove leading and trailing whitespaces and line breaks." },
"resolveResource": { "index": 7, "kind": "attribute", "displayName":
"Resolve Resource", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether a result of the expression that is a String starting with resource: is
loaded as a resource and its content becomes the result, e.g. a script that
returns resource:file:order.json o [...]
diff --git
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
index d3c1a3ef82db..d7286003a364 100644
---
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
+++
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
@@ -20,7 +20,7 @@
"expression": { "index": 1, "kind": "value", "displayName": "Expression",
"group": "common", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The expression value in your chosen language syntax." },
"trimResult": { "index": 2, "kind": "attribute", "displayName": "Trim
Result", "group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to trim the returned values when
this language is in use." },
"pretty": { "index": 3, "kind": "attribute", "displayName": "Pretty",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "To pretty format the output (only JSon
or XML supported)." },
- "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If the result is a
nested simple expression should this expression be evaluated as well." },
+ "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "security", "label": "advanced,security", "required": false, "type":
"boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired":
false, "secret": false, "security": "insecure:dev", "defaultValue": false,
"description": "If the result is a nested simple expression should this
expression be evaluated as well." },
"resultType": { "index": 5, "kind": "attribute", "displayName": "Result
Type", "group": "common", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The class of the result type (type from output)." },
"trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "group":
"advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": true, "description": "Whether to trim the
source code to remove leading and trailing whitespaces and line breaks." },
"resolveResource": { "index": 7, "kind": "attribute", "displayName":
"Resolve Resource", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether a result of the expression that is a String starting with resource: is
loaded as a resource and its content becomes the result, e.g. a script that
returns resource:file:order.json o [...]
diff --git
a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/language/simple.json
b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/language/simple.json
index 16ae4e0aa725..54a83ef0c577 100644
---
a/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/language/simple.json
+++
b/core/camel-core-model/src/generated/resources/META-INF/org/apache/camel/model/language/simple.json
@@ -17,7 +17,7 @@
"expression": { "index": 1, "kind": "value", "displayName": "Expression",
"group": "common", "required": true, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The expression value in your chosen language syntax." },
"trimResult": { "index": 2, "kind": "attribute", "displayName": "Trim
Result", "group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether to trim the returned values when
this language is in use." },
"pretty": { "index": 3, "kind": "attribute", "displayName": "Pretty",
"group": "common", "required": false, "type": "boolean", "javaType":
"java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "To pretty format the output (only JSon
or XML supported)." },
- "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "description": "If the result is a
nested simple expression should this expression be evaluated as well." },
+ "nested": { "index": 4, "kind": "attribute", "displayName": "Nested",
"group": "security", "label": "advanced,security", "required": false, "type":
"boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired":
false, "secret": false, "security": "insecure:dev", "defaultValue": false,
"description": "If the result is a nested simple expression should this
expression be evaluated as well." },
"resultType": { "index": 5, "kind": "attribute", "displayName": "Result
Type", "group": "common", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"description": "The class of the result type (type from output)." },
"trim": { "index": 6, "kind": "attribute", "displayName": "Trim", "group":
"advanced", "label": "advanced", "required": false, "type": "boolean",
"javaType": "java.lang.Boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": true, "description": "Whether to trim the
source code to remove leading and trailing whitespaces and line breaks." },
"resolveResource": { "index": 7, "kind": "attribute", "displayName":
"Resolve Resource", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether a result of the expression that is a String starting with resource: is
loaded as a resource and its content becomes the result, e.g. a script that
returns resource:file:order.json o [...]
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/language/SimpleExpression.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/language/SimpleExpression.java
index 185efe73ba12..aa457250cde0 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/language/SimpleExpression.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/language/SimpleExpression.java
@@ -43,7 +43,8 @@ public class SimpleExpression extends
TypedExpressionDefinition {
description = "To pretty format the output (only JSon or XML
supported).")
private String pretty;
@XmlAttribute
- @Metadata(defaultValue = "false", javaType = "java.lang.Boolean", label =
"advanced",
+ @Metadata(defaultValue = "false", javaType = "java.lang.Boolean", label =
"advanced,security",
+ security = "insecure:dev",
description = "If the result is a nested simple expression
should this expression be evaluated as well.")
private String nested;
diff --git
a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
index 654991dac107..b0a785925b59 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
@@ -80,6 +80,7 @@ public final class SecurityUtils {
map.put("ignoresslverification", new SecurityOption(INSECURE_SSL,
"true"));
map.put("ignoresslwarnings", new SecurityOption(INSECURE_SSL, "true"));
map.put("knownhostsresource", new SecurityOption(INSECURE_SSL, ""));
+ map.put("nested", new SecurityOption(INSECURE_DEV, "true"));
map.put("objectcodecpattern", new
SecurityOption(INSECURE_SERIALIZATION, ""));
map.put("objectmessageenabled", new
SecurityOption(INSECURE_SERIALIZATION, "true"));
map.put("sendenabled", new SecurityOption(INSECURE_DEV, "true"));
@@ -170,6 +171,9 @@ public final class SecurityUtils {
"component:oaipmh"));
owners.put("knownhostsresource", Set.of(
"component:ssh"));
+ owners.put("nested", Set.of(
+ "language:file",
+ "language:simple"));
owners.put("objectcodecpattern", Set.of(
"component:mina"));
owners.put("objectmessageenabled", Set.of(
@@ -293,7 +297,9 @@ public final class SecurityUtils {
* <p>
* A key that identifies a component, data format or language (such as
{@code camel.component.netty.ssl}) only
* matches a security option that this component, data format or language
declares. Any other key (such as a
- * camel-main option, or an option name without a prefix) matches by the
option name.
+ * camel-main option, or an option name without a prefix) matches by the
option name, except that a configuration
+ * key never matches an option that only languages declare (such as {@code
camel.beans.foo.nested} for the
+ * {@code nested} option of the simple language).
*
* @param text the configuration property key (e.g.,
"camel.component.aws2-s3.trustAllCertificates")
* @return the security option info, or null if the property has no
security category
@@ -308,10 +314,29 @@ public final class SecurityUtils {
// the option has the same name as a security option of
another component, data format or language
return null;
}
+ if (owner == null && owners != null && text.indexOf('.') >= 0 &&
isDeclaredByLanguagesOnly(owners)) {
+ // a language option is set on an expression in a route, which
is checked by its bare option name, or
+ // under camel.language.<name>. - any other configuration key
(camel.beans.*, camel.main.*, ...) that
+ // merely ends with the same name is not this option.
Component and data format options keep matching
+ // such keys by name, as camel.beans.* can configure a
component or data format bean.
+ return null;
+ }
}
return answer;
}
+ private static boolean isDeclaredByLanguagesOnly(Set<String> owners) {
+ if (owners.isEmpty()) {
+ return false;
+ }
+ for (String owner : owners) {
+ if (!owner.startsWith("language:")) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* The owner of a configuration property key that identifies a component,
data format or language, such as
* {@code component:nettyhttp} for {@code camel.component.netty-http.ssl},
or null for any other key.
diff --git
a/core/camel-util/src/test/java/org/apache/camel/util/SecurityUtilsTest.java
b/core/camel-util/src/test/java/org/apache/camel/util/SecurityUtilsTest.java
index 29e3606f25c3..ce1f1816ccd9 100644
--- a/core/camel-util/src/test/java/org/apache/camel/util/SecurityUtilsTest.java
+++ b/core/camel-util/src/test/java/org/apache/camel/util/SecurityUtilsTest.java
@@ -268,6 +268,39 @@ class SecurityUtilsTest {
assertNotNull(SecurityUtils.getSecurityOption("camel.main.devConsoleEnabled"));
}
+ @Test
+ void testLanguageOptionMatchesOnlyItsOwnLanguage() {
+ // nested is declared only by the simple and file languages
+
assertTrue(SecurityUtils.isInsecureValue("camel.language.simple.nested",
"true"));
+ assertTrue(SecurityUtils.isInsecureValue("camel.language.file.nested",
"true"));
+
assertNull(SecurityUtils.getSecurityOption("camel.language.xpath.nested"));
+ // the bare option name, as the security scanner checks an expression
in a route, still matches
+ assertTrue(SecurityUtils.isInsecureValue("nested", "true"));
+ // any other configuration key that merely ends with the same name is
not the language option
+ assertNull(SecurityUtils.getSecurityOption("camel.beans.foo.nested"));
+ assertNull(SecurityUtils.getSecurityOption("camel.main.nested"));
+
assertNull(SecurityUtils.getSecurityOption("camel.kamelet.myKamelet.nested"));
+ // component options keep matching such keys by name, as camel.beans.*
can configure a component bean
+
assertNotNull(SecurityUtils.getSecurityOption("camel.beans.myClient.trustAllCertificates"));
+ }
+
+ @Test
+ void testDetectViolationsIgnoresBeanPropertyNamedLikeALanguageOption() {
+ Map<String, Object> properties = new LinkedHashMap<>();
+ properties.put("camel.beans.foo.nested", "true");
+ properties.put("camel.language.simple.nested", "true");
+
+ List<SecurityViolation> violations = SecurityUtils.detectViolations(
+ properties,
+ (k, v) -> false,
+ category -> "fail",
+ Set.of());
+
+ assertEquals(1, violations.size());
+ assertEquals("camel.language.simple.nested",
violations.get(0).propertyKey());
+ assertEquals(SecurityUtils.INSECURE_DEV, violations.get(0).category());
+ }
+
@Test
void testDetectViolationsOnlyForTheOwningComponent() {
Map<String, Object> properties = new LinkedHashMap<>();
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanTools.java
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanTools.java
index 55a56b6cb54f..ca872b096ca0 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanTools.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanTools.java
@@ -146,6 +146,12 @@ public class SecurityScanTools {
if (idx < 0) {
return null;
}
+ // require a token boundary before the key, so a longer identifier
that merely ends in the key
+ // (isNested, unnested, an unrelated ...nested field) is not
treated as this option
+ if (idx > 0 && Character.isLetterOrDigit(normalized.charAt(idx -
1))) {
+ from = idx + 1;
+ continue;
+ }
int after = idx + optionKey.length();
// a quoted key ("key":value) leaves a closing quote before the
separator
if (after < normalized.length() && normalized.charAt(after) ==
'"') {
diff --git
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanToolsTest.java
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanToolsTest.java
index 0e7ca9da2beb..45e74ef7bb80 100644
---
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanToolsTest.java
+++
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/SecurityScanToolsTest.java
@@ -69,6 +69,59 @@ class SecurityScanToolsTest {
&& f.category().equals("insecure:ssl"));
}
+ @Test
+ void securityOptionMatchingIsAnchoredOnTokenBoundaries() {
+ // startTls ends in the "tls" security option but is a different
option; without a token-boundary check it was
+ // reported as an insecure tls=false
+ SecurityScanTools.SecurityScanResult falsePositive =
tools.camel_security_scan("""
+ - route:
+ from:
+ uri: smtp://mail.example.com?startTls=false
+ """, "yaml");
+ assertThat(falsePositive.findings()).noneMatch(f ->
f.issue().contains("tls="));
+
+ // a boundary-delimited tls=false is still detected
+ SecurityScanTools.SecurityScanResult real =
tools.camel_security_scan("""
+ - route:
+ from:
+ uri: netty://host:9999?tls=false
+ """, "yaml");
+ assertThat(real.findings())
+ .anyMatch(f -> f.issue().contains("tls=false") &&
f.category().equals("insecure:ssl"));
+ }
+
+ @Test
+ void detectsNestedSimpleExpression() {
+ // nested=true evaluates the result of the expression as another
simple expression
+ SecurityScanTools.SecurityScanResult nested =
tools.camel_security_scan("""
+ - route:
+ from:
+ uri: direct:start
+ steps:
+ - setBody:
+ simple:
+ expression: "${header.template}"
+ nested: true
+ """, "yaml");
+ assertThat(nested.findings())
+ .anyMatch(f -> f.issue().contains("nested=true") &&
f.category().equals("insecure:dev"));
+
+ SecurityScanTools.SecurityScanResult notNested =
tools.camel_security_scan("""
+ - route:
+ from:
+ uri: direct:start
+ steps:
+ - setBody:
+ simple:
+ expression: "${header.template}"
+ nested: false
+ - setHeader:
+ name: isNested
+ constant: "unnested: true"
+ """, "yaml");
+ assertThat(notNested.findings()).noneMatch(f ->
f.issue().contains("nested="));
+ }
+
@Test
void detectsAllowJavaSerializedObject() {
String route = """
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
index 6c97b9d7b50c..3b2a2b3e4daf 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
@@ -16118,8 +16118,8 @@
"displayName" : "Nested",
"kind" : "attribute",
"index" : 4,
- "group" : "advanced",
- "label" : "advanced"
+ "group" : "security",
+ "label" : "advanced,security"
}, {
"name" : "resultType",
"type" : "string",