This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-26551-dapr-secret-headers
in repository https://gitbox.apache.org/repos/asf/camel.git

commit e160e2c9665a333abfe621a64efbd6d747c31ada
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Nov 5 21:29:32 2026 +0100

    CAMEL-26551: camel-dapr - honour the secret store and key headers for the 
secret operation only with allowSecretStoreAndKeyFromHeaders=true
    
    The secret operation took the secret store and the key from the
    CamelDaprSecretStore and CamelDaprKey headers first, and the endpoint 
options
    only when no header was set, so a message could read another secret or use
    another secret store than the endpoint is configured with.
    
    The secret operation now uses the secretStore and key options of the 
endpoint,
    and the two headers only when the new allowSecretStoreAndKeyFromHeaders 
option
    is enabled (disabled by default). An endpoint without a key fails with an 
error
    naming the option when the message has a CamelDaprKey header, instead of
    reading all the secrets of the store. The state operations still take the 
key
    from the CamelDaprKey header. The component page lists the headers that
    override the endpoint, and the upgrade guide has an entry.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../org/apache/camel/catalog/components/dapr.json  | 10 ++--
 .../apache/camel/catalog/docs/dapr-component.adoc  | 10 ++++
 .../component/dapr/DaprComponentConfigurer.java    |  6 +++
 .../component/dapr/DaprEndpointConfigurer.java     |  6 +++
 .../component/dapr/DaprEndpointUriFactory.java     |  3 +-
 .../org/apache/camel/component/dapr/dapr.json      | 10 ++--
 .../camel-dapr/src/main/docs/dapr-component.adoc   | 10 ++++
 .../camel/component/dapr/DaprConfiguration.java    | 18 +++++++
 .../dapr/DaprConfigurationOptionsProxy.java        | 17 +++++-
 .../apache/camel/component/dapr/DaprConstants.java |  8 ++-
 .../dapr/operations/DaprSecretHandler.java         | 19 ++++++-
 .../dapr/DaprConfigurationOptionsProxyTest.java    | 22 ++++++++
 .../camel/component/dapr/DaprProducerTest.java     | 60 ++++++++++++++++++++++
 .../java/org/apache/camel/util/SecurityUtils.java  |  3 ++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    | 16 ++++++
 .../component/dsl/DaprComponentBuilderFactory.java | 22 ++++++++
 .../endpoint/dsl/DaprEndpointBuilderFactory.java   | 46 ++++++++++++++++-
 17 files changed, 271 insertions(+), 15 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/dapr.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/dapr.json
index 5828a5b38408..8efa79dba04a 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/dapr.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/dapr.json
@@ -63,7 +63,8 @@
     "workflowStartTime": { "index": 36, "kind": "property", "displayName": 
"Workflow Start Time", "group": "producer", "label": "producer", "required": 
false, "type": "object", "javaType": "java.time.Instant", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.dapr.DaprConfiguration", "configurationField": 
"configuration", "description": "The start time of the new workflow" },
     "workflowVersion": { "index": 37, "kind": "property", "displayName": 
"Workflow Version", "group": "producer", "label": "producer", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.dapr.DaprConfiguration", "configurationField": 
"configuration", "description": "The version of the workflow to start" },
     "autowiredEnabled": { "index": 38, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching  [...]
-    "headerFilterStrategy": { "index": 39, "kind": "property", "displayName": 
"Header Filter Strategy", "group": "advanced", "label": "advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." }
+    "headerFilterStrategy": { "index": 39, "kind": "property", "displayName": 
"Header Filter Strategy", "group": "advanced", "label": "advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." },
+    "allowSecretStoreAndKeyFromHeaders": { "index": 40, "kind": "property", 
"displayName": "Allow Secret Store And Key From Headers", "group": "security", 
"label": "producer,security", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"security": "insecure:dev", "insecureValue": "true", "defaultValue": false, 
"configurationClass": "org.apache.camel.component.dapr.DaprConfiguration", 
"configurationField": "configuration" [...]
   },
   "headers": {
     "CamelDaprServiceToInvoke": { "index": 0, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Target service to invoke. Can be a Dapr App 
ID, a named HTTPEndpoint, or a FQDN\/public URL", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#SERVICE_TO_INVOKE" },
@@ -74,9 +75,9 @@
     "CamelDaprHttpExtension": { "index": 5, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"HttpExtension", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The HttpExtension object for service 
invocation. Takes precedence over verb", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#HTTP_EXTENSION" },
     "CamelDaprStateOperation": { "index": 6, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"StateOperation", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": "get", "description": "The state 
operation to perform on the state store. Required for DaprOperation.state 
operation", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#STATE_OPERATION" },
     "CamelDaprStateStore": { "index": 7, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The name of the Dapr state store to interact 
with, defined in statestore.yaml config", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#STATE_STORE" },
-    "CamelDaprSecretStore": { "index": 8, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The name of the Dapr secret store to interact 
with, defined in local-secret-store.yaml config", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#SECRET_STORE" },
+    "CamelDaprSecretStore": { "index": 8, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The name of the Dapr secret store to interact 
with, defined in local-secret-store.yaml config. For the secret operation, this 
header is ignored unless the endpoint enables 
allowSecretStoreAndKeyFromHeaders=true (disabled by default). [...]
     "CamelDaprConfigStore": { "index": 9, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The name of the Dapr config store to interact 
with, defined in statestore.yaml config", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#CONFIG_STORE" },
-    "CamelDaprKey": { "index": 10, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The key used to identify the state\/secret 
object within the specified state\/secret store", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#KEY" },
+    "CamelDaprKey": { "index": 10, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The key used to identify the state\/secret 
object within the specified state\/secret store. For the secret operation, this 
header is ignored unless the endpoint enables 
allowSecretStoreAndKeyFromHeaders=true (disabled by default).", "consta [...]
     "CamelDaprETag": { "index": 11, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The eTag for optimistic concurrency during 
state save or delete operations", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#E_TAG" },
     "CamelDaprConcurrency": { "index": 12, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"io.dapr.client.domain.StateOptions.Concurrency", "enum": [ "FIRST_WRITE", 
"LAST_WRITE" ], "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Concurrency mode to use with state 
operations", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#CONCURRENCY" },
     "CamelDaprConsistency": { "index": 13, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"io.dapr.client.domain.StateOptions.Consistency", "enum": [ "EVENTUAL", 
"STRONG" ], "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Consistency level to use with state 
operations", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#CONSISTENCY" },
@@ -171,6 +172,7 @@
     "workflowStartTime": { "index": 37, "kind": "parameter", "displayName": 
"Workflow Start Time", "group": "producer", "label": "producer", "required": 
false, "type": "object", "javaType": "java.time.Instant", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.dapr.DaprConfiguration", "configurationField": 
"configuration", "description": "The start time of the new workflow" },
     "workflowVersion": { "index": 38, "kind": "parameter", "displayName": 
"Workflow Version", "group": "producer", "label": "producer", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.dapr.DaprConfiguration", "configurationField": 
"configuration", "description": "The version of the workflow to start" },
     "lazyStartProducer": { "index": 39, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
-    "headerFilterStrategy": { "index": 40, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "advanced", "label": "advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." }
+    "headerFilterStrategy": { "index": 40, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "advanced", "label": "advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." },
+    "allowSecretStoreAndKeyFromHeaders": { "index": 41, "kind": "parameter", 
"displayName": "Allow Secret Store And Key From Headers", "group": "security", 
"label": "producer,security", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"security": "insecure:dev", "insecureValue": "true", "defaultValue": false, 
"configurationClass": "org.apache.camel.component.dapr.DaprConfiguration", 
"configurationField": "configuration [...]
   }
 }
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/dapr-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/dapr-component.adoc
index cce7ea2f74c4..b739cc7105c2 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/dapr-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/dapr-component.adoc
@@ -64,6 +64,8 @@ Dapr’s bindings building block allows interaction with 
external systems via in
 === 4. *secret*:
 Dapr’s secret management building block enables secure retrieval of secrets 
from external secret stores. The secret operation fetches a secret from the 
specified secret store. If a key is provided, the operation retrieves the 
corresponding secret; if no key is specified, a bulk retrieval of all secrets 
from the store is performed. This operation requires the secretStore name, and 
optionally the key.
 
+The secret operation reads the secret store and the key of the endpoint. The 
`CamelDaprSecretStore` and `CamelDaprKey` headers are ignored unless the 
endpoint sets `allowSecretStoreAndKeyFromHeaders=true`. An endpoint without a 
key fails, instead of reading all the secrets of the store, when the message 
has a `CamelDaprKey` header that it ignores.
+
 === 5. *configuration*:
 Dapr’s configuration building block allows applications to retrieve dynamic 
configuration values from external configuration stores. The configuration 
operation fetches values associated with keys specified in configKeys. This 
operation requires the configStore name, and the configKeys.
 
@@ -96,6 +98,14 @@ Dapr Workflows enable developers to write long-running, 
persistent, and reliable
 |`raiseEvent` |Sends an event to a running workflow instance that is waiting 
for it. Requires `workflowInstanceId` and `eventName`. The message body is used 
as the event payload.
 |===
 
+=== Headers that override the endpoint
+
+The producer headers, such as `CamelDaprServiceToInvoke`, 
`CamelDaprStateStore`, `CamelDaprKey`, `CamelDaprPubSubName`, `CamelDaprTopic`, 
`CamelDaprBindingName`, `CamelDaprStoreName` or `CamelDaprWorkflowInstanceId`, 
take the place of the endpoint option of the same name for one message. The 
`CamelDaprMetadata` header gives the metadata that the operation sends to the 
Dapr building block.
+
+For the `secret` operation, the `CamelDaprSecretStore` and `CamelDaprKey` 
headers are ignored unless the endpoint sets 
`allowSecretStoreAndKeyFromHeaders=true`. With that option, they take the place 
of the secret store and the key of the endpoint for one message, so the message 
chooses the secret that the operation reads.
+
+As the producer keeps the headers of the message, a `CamelDapr*` header also 
applies to the next `dapr` call of the route. When the messages come from an 
untrusted producer through a consumer that does not filter out `Camel*` 
headers, or when a `dapr` call must use only the options of its endpoint, 
remove these headers with `removeHeaders("CamelDapr*")` before the `dapr` 
endpoint.
+
 === Dapr Consumer operations
 
 === 1. *pubSub*:
diff --git 
a/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprComponentConfigurer.java
 
b/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprComponentConfigurer.java
index bb88f2a62e15..02f1e2d1e67a 100644
--- 
a/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprComponentConfigurer.java
+++ 
b/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprComponentConfigurer.java
@@ -31,6 +31,8 @@ public class DaprComponentConfigurer extends 
PropertyConfigurerSupport implement
     public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
         DaprComponent target = (DaprComponent) obj;
         switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+        case "allowsecretstoreandkeyfromheaders":
+        case "allowSecretStoreAndKeyFromHeaders": 
getOrCreateConfiguration(target).setAllowSecretStoreAndKeyFromHeaders(property(camelContext,
 boolean.class, value)); return true;
         case "autowiredenabled":
         case "autowiredEnabled": 
target.setAutowiredEnabled(property(camelContext, boolean.class, value)); 
return true;
         case "bindingname":
@@ -114,6 +116,8 @@ public class DaprComponentConfigurer extends 
PropertyConfigurerSupport implement
     @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+        case "allowsecretstoreandkeyfromheaders":
+        case "allowSecretStoreAndKeyFromHeaders": return boolean.class;
         case "autowiredenabled":
         case "autowiredEnabled": return boolean.class;
         case "bindingname":
@@ -193,6 +197,8 @@ public class DaprComponentConfigurer extends 
PropertyConfigurerSupport implement
     public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
         DaprComponent target = (DaprComponent) obj;
         switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+        case "allowsecretstoreandkeyfromheaders":
+        case "allowSecretStoreAndKeyFromHeaders": return 
getOrCreateConfiguration(target).isAllowSecretStoreAndKeyFromHeaders();
         case "autowiredenabled":
         case "autowiredEnabled": return target.isAutowiredEnabled();
         case "bindingname":
diff --git 
a/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprEndpointConfigurer.java
 
b/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprEndpointConfigurer.java
index 303a9be2d44c..4b1ce7fc4f2a 100644
--- 
a/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprEndpointConfigurer.java
+++ 
b/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprEndpointConfigurer.java
@@ -24,6 +24,8 @@ public class DaprEndpointConfigurer extends 
PropertyConfigurerSupport implements
     public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
         DaprEndpoint target = (DaprEndpoint) obj;
         switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+        case "allowsecretstoreandkeyfromheaders":
+        case "allowSecretStoreAndKeyFromHeaders": 
target.getConfiguration().setAllowSecretStoreAndKeyFromHeaders(property(camelContext,
 boolean.class, value)); return true;
         case "bindingname":
         case "bindingName": 
target.getConfiguration().setBindingName(property(camelContext, 
java.lang.String.class, value)); return true;
         case "bindingoperation":
@@ -108,6 +110,8 @@ public class DaprEndpointConfigurer extends 
PropertyConfigurerSupport implements
     @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+        case "allowsecretstoreandkeyfromheaders":
+        case "allowSecretStoreAndKeyFromHeaders": return boolean.class;
         case "bindingname":
         case "bindingName": return java.lang.String.class;
         case "bindingoperation":
@@ -188,6 +192,8 @@ public class DaprEndpointConfigurer extends 
PropertyConfigurerSupport implements
     public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
         DaprEndpoint target = (DaprEndpoint) obj;
         switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
+        case "allowsecretstoreandkeyfromheaders":
+        case "allowSecretStoreAndKeyFromHeaders": return 
target.getConfiguration().isAllowSecretStoreAndKeyFromHeaders();
         case "bindingname":
         case "bindingName": return target.getConfiguration().getBindingName();
         case "bindingoperation":
diff --git 
a/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprEndpointUriFactory.java
 
b/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprEndpointUriFactory.java
index e62127132c54..1e286312b7d7 100644
--- 
a/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprEndpointUriFactory.java
+++ 
b/components/camel-dapr/src/generated/java/org/apache/camel/component/dapr/DaprEndpointUriFactory.java
@@ -24,7 +24,8 @@ public class DaprEndpointUriFactory extends 
org.apache.camel.support.component.E
     private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(41);
+        Set<String> props = new HashSet<>(42);
+        props.add("allowSecretStoreAndKeyFromHeaders");
         props.add("bindingName");
         props.add("bindingOperation");
         props.add("bridgeErrorHandler");
diff --git 
a/components/camel-dapr/src/generated/resources/META-INF/org/apache/camel/component/dapr/dapr.json
 
b/components/camel-dapr/src/generated/resources/META-INF/org/apache/camel/component/dapr/dapr.json
index 5828a5b38408..8efa79dba04a 100644
--- 
a/components/camel-dapr/src/generated/resources/META-INF/org/apache/camel/component/dapr/dapr.json
+++ 
b/components/camel-dapr/src/generated/resources/META-INF/org/apache/camel/component/dapr/dapr.json
@@ -63,7 +63,8 @@
     "workflowStartTime": { "index": 36, "kind": "property", "displayName": 
"Workflow Start Time", "group": "producer", "label": "producer", "required": 
false, "type": "object", "javaType": "java.time.Instant", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.dapr.DaprConfiguration", "configurationField": 
"configuration", "description": "The start time of the new workflow" },
     "workflowVersion": { "index": 37, "kind": "property", "displayName": 
"Workflow Version", "group": "producer", "label": "producer", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.dapr.DaprConfiguration", "configurationField": 
"configuration", "description": "The version of the workflow to start" },
     "autowiredEnabled": { "index": 38, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching  [...]
-    "headerFilterStrategy": { "index": 39, "kind": "property", "displayName": 
"Header Filter Strategy", "group": "advanced", "label": "advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." }
+    "headerFilterStrategy": { "index": 39, "kind": "property", "displayName": 
"Header Filter Strategy", "group": "advanced", "label": "advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." },
+    "allowSecretStoreAndKeyFromHeaders": { "index": 40, "kind": "property", 
"displayName": "Allow Secret Store And Key From Headers", "group": "security", 
"label": "producer,security", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"security": "insecure:dev", "insecureValue": "true", "defaultValue": false, 
"configurationClass": "org.apache.camel.component.dapr.DaprConfiguration", 
"configurationField": "configuration" [...]
   },
   "headers": {
     "CamelDaprServiceToInvoke": { "index": 0, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Target service to invoke. Can be a Dapr App 
ID, a named HTTPEndpoint, or a FQDN\/public URL", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#SERVICE_TO_INVOKE" },
@@ -74,9 +75,9 @@
     "CamelDaprHttpExtension": { "index": 5, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"HttpExtension", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The HttpExtension object for service 
invocation. Takes precedence over verb", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#HTTP_EXTENSION" },
     "CamelDaprStateOperation": { "index": 6, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"StateOperation", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": "get", "description": "The state 
operation to perform on the state store. Required for DaprOperation.state 
operation", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#STATE_OPERATION" },
     "CamelDaprStateStore": { "index": 7, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The name of the Dapr state store to interact 
with, defined in statestore.yaml config", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#STATE_STORE" },
-    "CamelDaprSecretStore": { "index": 8, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The name of the Dapr secret store to interact 
with, defined in local-secret-store.yaml config", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#SECRET_STORE" },
+    "CamelDaprSecretStore": { "index": 8, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The name of the Dapr secret store to interact 
with, defined in local-secret-store.yaml config. For the secret operation, this 
header is ignored unless the endpoint enables 
allowSecretStoreAndKeyFromHeaders=true (disabled by default). [...]
     "CamelDaprConfigStore": { "index": 9, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The name of the Dapr config store to interact 
with, defined in statestore.yaml config", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#CONFIG_STORE" },
-    "CamelDaprKey": { "index": 10, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The key used to identify the state\/secret 
object within the specified state\/secret store", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#KEY" },
+    "CamelDaprKey": { "index": 10, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The key used to identify the state\/secret 
object within the specified state\/secret store. For the secret operation, this 
header is ignored unless the endpoint enables 
allowSecretStoreAndKeyFromHeaders=true (disabled by default).", "consta [...]
     "CamelDaprETag": { "index": 11, "kind": "header", "displayName": "", 
"group": "producer", "label": "producer", "required": false, "javaType": 
"String", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The eTag for optimistic concurrency during 
state save or delete operations", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#E_TAG" },
     "CamelDaprConcurrency": { "index": 12, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"io.dapr.client.domain.StateOptions.Concurrency", "enum": [ "FIRST_WRITE", 
"LAST_WRITE" ], "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Concurrency mode to use with state 
operations", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#CONCURRENCY" },
     "CamelDaprConsistency": { "index": 13, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"io.dapr.client.domain.StateOptions.Consistency", "enum": [ "EVENTUAL", 
"STRONG" ], "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "Consistency level to use with state 
operations", "constantName": 
"org.apache.camel.component.dapr.DaprConstants#CONSISTENCY" },
@@ -171,6 +172,7 @@
     "workflowStartTime": { "index": 37, "kind": "parameter", "displayName": 
"Workflow Start Time", "group": "producer", "label": "producer", "required": 
false, "type": "object", "javaType": "java.time.Instant", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.dapr.DaprConfiguration", "configurationField": 
"configuration", "description": "The start time of the new workflow" },
     "workflowVersion": { "index": 38, "kind": "parameter", "displayName": 
"Workflow Version", "group": "producer", "label": "producer", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.dapr.DaprConfiguration", "configurationField": 
"configuration", "description": "The version of the workflow to start" },
     "lazyStartProducer": { "index": 39, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
-    "headerFilterStrategy": { "index": 40, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "advanced", "label": "advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." }
+    "headerFilterStrategy": { "index": 40, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "advanced", "label": "advanced", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." },
+    "allowSecretStoreAndKeyFromHeaders": { "index": 41, "kind": "parameter", 
"displayName": "Allow Secret Store And Key From Headers", "group": "security", 
"label": "producer,security", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"security": "insecure:dev", "insecureValue": "true", "defaultValue": false, 
"configurationClass": "org.apache.camel.component.dapr.DaprConfiguration", 
"configurationField": "configuration [...]
   }
 }
diff --git a/components/camel-dapr/src/main/docs/dapr-component.adoc 
b/components/camel-dapr/src/main/docs/dapr-component.adoc
index cce7ea2f74c4..b739cc7105c2 100644
--- a/components/camel-dapr/src/main/docs/dapr-component.adoc
+++ b/components/camel-dapr/src/main/docs/dapr-component.adoc
@@ -64,6 +64,8 @@ Dapr’s bindings building block allows interaction with 
external systems via in
 === 4. *secret*:
 Dapr’s secret management building block enables secure retrieval of secrets 
from external secret stores. The secret operation fetches a secret from the 
specified secret store. If a key is provided, the operation retrieves the 
corresponding secret; if no key is specified, a bulk retrieval of all secrets 
from the store is performed. This operation requires the secretStore name, and 
optionally the key.
 
+The secret operation reads the secret store and the key of the endpoint. The 
`CamelDaprSecretStore` and `CamelDaprKey` headers are ignored unless the 
endpoint sets `allowSecretStoreAndKeyFromHeaders=true`. An endpoint without a 
key fails, instead of reading all the secrets of the store, when the message 
has a `CamelDaprKey` header that it ignores.
+
 === 5. *configuration*:
 Dapr’s configuration building block allows applications to retrieve dynamic 
configuration values from external configuration stores. The configuration 
operation fetches values associated with keys specified in configKeys. This 
operation requires the configStore name, and the configKeys.
 
@@ -96,6 +98,14 @@ Dapr Workflows enable developers to write long-running, 
persistent, and reliable
 |`raiseEvent` |Sends an event to a running workflow instance that is waiting 
for it. Requires `workflowInstanceId` and `eventName`. The message body is used 
as the event payload.
 |===
 
+=== Headers that override the endpoint
+
+The producer headers, such as `CamelDaprServiceToInvoke`, 
`CamelDaprStateStore`, `CamelDaprKey`, `CamelDaprPubSubName`, `CamelDaprTopic`, 
`CamelDaprBindingName`, `CamelDaprStoreName` or `CamelDaprWorkflowInstanceId`, 
take the place of the endpoint option of the same name for one message. The 
`CamelDaprMetadata` header gives the metadata that the operation sends to the 
Dapr building block.
+
+For the `secret` operation, the `CamelDaprSecretStore` and `CamelDaprKey` 
headers are ignored unless the endpoint sets 
`allowSecretStoreAndKeyFromHeaders=true`. With that option, they take the place 
of the secret store and the key of the endpoint for one message, so the message 
chooses the secret that the operation reads.
+
+As the producer keeps the headers of the message, a `CamelDapr*` header also 
applies to the next `dapr` call of the route. When the messages come from an 
untrusted producer through a consumer that does not filter out `Camel*` 
headers, or when a `dapr` call must use only the options of its endpoint, 
remove these headers with `removeHeaders("CamelDapr*")` before the `dapr` 
endpoint.
+
 === Dapr Consumer operations
 
 === 1. *pubSub*:
diff --git 
a/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConfiguration.java
 
b/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConfiguration.java
index 26c8ccdefd09..29fae4c28ad2 100644
--- 
a/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConfiguration.java
+++ 
b/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConfiguration.java
@@ -75,6 +75,12 @@ public class DaprConfiguration implements Cloneable {
     @UriParam(label = "producer",
               description = "The key used to identify the state/secret object 
within the specified state/secret store")
     private String key;
+    @UriParam(label = "producer,security", defaultValue = "false", security = 
"insecure:dev", insecureValue = "true",
+              description = "Whether to allow overriding the secret store and 
the key of the endpoint with the"
+                            + " CamelDaprSecretStore and CamelDaprKey headers 
for the secret operation. Disabled by"
+                            + " default; enable it only when the header source 
is trusted, since it lets a message"
+                            + " choose the secret store and the secret that 
the secret operation reads.")
+    private boolean allowSecretStoreAndKeyFromHeaders;
     @UriParam(label = "producer", description = "The eTag for optimistic 
concurrency during state save or delete operations")
     private String eTag;
     @UriParam(label = "producer", description = "Concurrency mode to use with 
state operations",
@@ -298,6 +304,18 @@ public class DaprConfiguration implements Cloneable {
         this.key = key;
     }
 
+    /**
+     * Whether the <b>CamelDaprSecretStore</b> and <b>CamelDaprKey</b> headers 
may override the secret store and the key
+     * of the endpoint for the secret operation.
+     */
+    public boolean isAllowSecretStoreAndKeyFromHeaders() {
+        return allowSecretStoreAndKeyFromHeaders;
+    }
+
+    public void setAllowSecretStoreAndKeyFromHeaders(boolean 
allowSecretStoreAndKeyFromHeaders) {
+        this.allowSecretStoreAndKeyFromHeaders = 
allowSecretStoreAndKeyFromHeaders;
+    }
+
     /**
      * ETag used for <b>optimistic concurrency</b> during state save or delete 
operations.
      * <p>
diff --git 
a/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConfigurationOptionsProxy.java
 
b/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConfigurationOptionsProxy.java
index dd651b00745e..87af87f3e6bb 100644
--- 
a/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConfigurationOptionsProxy.java
+++ 
b/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConfigurationOptionsProxy.java
@@ -79,8 +79,23 @@ public class DaprConfigurationOptionsProxy {
         return getOption(DaprExchangeHeaders::getStateStoreFromHeaders, 
configuration::getStateStore, exchange);
     }
 
+    // the secret store and key headers may only make the secret operation 
read another secret when the endpoint opts in
     public String getSecretStore(final Exchange exchange) {
-        return getOption(DaprExchangeHeaders::getSecretStoreFromHeaders, 
configuration::getSecretStore, exchange);
+        if (configuration.isAllowSecretStoreAndKeyFromHeaders()) {
+            return getOption(DaprExchangeHeaders::getSecretStoreFromHeaders, 
configuration::getSecretStore, exchange);
+        }
+        return configuration.getSecretStore();
+    }
+
+    public String getSecretKey(final Exchange exchange) {
+        if (configuration.isAllowSecretStoreAndKeyFromHeaders()) {
+            return getKey(exchange);
+        }
+        return configuration.getKey();
+    }
+
+    public boolean isAllowSecretStoreAndKeyFromHeaders() {
+        return configuration.isAllowSecretStoreAndKeyFromHeaders();
     }
 
     public String getConfigStore(final Exchange exchange) {
diff --git 
a/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConstants.java
 
b/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConstants.java
index be4a21aa64df..7edf85de3efd 100644
--- 
a/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConstants.java
+++ 
b/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/DaprConstants.java
@@ -49,7 +49,9 @@ public class DaprConstants {
               javaType = "String")
     public static final String STATE_STORE = HEADER_PREFIX + "StateStore";
     @Metadata(label = "producer",
-              description = "The name of the Dapr secret store to interact 
with, defined in local-secret-store.yaml config",
+              description = "The name of the Dapr secret store to interact 
with, defined in local-secret-store.yaml config."
+                            + " For the secret operation, this header is 
ignored unless the endpoint enables"
+                            + " allowSecretStoreAndKeyFromHeaders=true 
(disabled by default).",
               javaType = "String")
     public static final String SECRET_STORE = HEADER_PREFIX + "SecretStore";
     @Metadata(label = "producer",
@@ -57,7 +59,9 @@ public class DaprConstants {
               javaType = "String")
     public static final String CONFIG_STORE = HEADER_PREFIX + "ConfigStore";
     @Metadata(label = "producer",
-              description = "The key used to identify the state/secret object 
within the specified state/secret store",
+              description = "The key used to identify the state/secret object 
within the specified state/secret store."
+                            + " For the secret operation, this header is 
ignored unless the endpoint enables"
+                            + " allowSecretStoreAndKeyFromHeaders=true 
(disabled by default).",
               javaType = "String")
     public static final String KEY = HEADER_PREFIX + "Key";
     @Metadata(label = "producer", description = "The eTag for optimistic 
concurrency during state save or delete operations",
diff --git 
a/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/operations/DaprSecretHandler.java
 
b/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/operations/DaprSecretHandler.java
index 5c4cc21c0d3e..af87990102c9 100644
--- 
a/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/operations/DaprSecretHandler.java
+++ 
b/components/camel-dapr/src/main/java/org/apache/camel/component/dapr/operations/DaprSecretHandler.java
@@ -23,7 +23,9 @@ import io.dapr.client.domain.GetBulkSecretRequest;
 import io.dapr.client.domain.GetSecretRequest;
 import org.apache.camel.Exchange;
 import org.apache.camel.component.dapr.DaprConfigurationOptionsProxy;
+import org.apache.camel.component.dapr.DaprConstants;
 import org.apache.camel.component.dapr.DaprEndpoint;
+import org.apache.camel.component.dapr.DaprExchangeHeaders;
 import org.apache.camel.util.ObjectHelper;
 
 public class DaprSecretHandler implements DaprOperationHandler {
@@ -39,7 +41,7 @@ public class DaprSecretHandler implements 
DaprOperationHandler {
     @Override
     public DaprOperationResponse handle(Exchange exchange) {
         String secretStore = 
configurationOptionsProxy.getSecretStore(exchange);
-        String key = configurationOptionsProxy.getKey(exchange);
+        String key = configurationOptionsProxy.getSecretKey(exchange);
         Map<String, String> metadata = 
configurationOptionsProxy.getMetadata(exchange);
         DaprClient client = endpoint.getClient();
 
@@ -62,7 +64,22 @@ public class DaprSecretHandler implements 
DaprOperationHandler {
         String secretStore = 
configurationOptionsProxy.getSecretStore(exchange);
 
         if (ObjectHelper.isEmpty(secretStore)) {
+            if 
(!configurationOptionsProxy.isAllowSecretStoreAndKeyFromHeaders()
+                    && 
ObjectHelper.isNotEmpty(DaprExchangeHeaders.getSecretStoreFromHeaders(exchange)))
 {
+                throw new IllegalArgumentException(
+                        "secretStore is mandatory to get secret. The " + 
DaprConstants.SECRET_STORE
+                                                   + " header is ignored 
unless allowSecretStoreAndKeyFromHeaders=true");
+            }
             throw new IllegalArgumentException("secretStore is mandatory to 
get secret");
         }
+        // without a key the endpoint reads all the secrets of the store, so 
the key header must not be silently ignored
+        if (!configurationOptionsProxy.isAllowSecretStoreAndKeyFromHeaders()
+                && 
ObjectHelper.isEmpty(configurationOptionsProxy.getSecretKey(exchange))
+                && 
ObjectHelper.isNotEmpty(DaprExchangeHeaders.getKeyFromHeaders(exchange))) {
+            throw new IllegalArgumentException(
+                    "The " + DaprConstants.KEY + " header is ignored by the 
secret operation unless"
+                                               + " 
allowSecretStoreAndKeyFromHeaders=true. Set the key option on the"
+                                               + " endpoint, or remove the 
header to get all the secrets of the store");
+        }
     }
 }
diff --git 
a/components/camel-dapr/src/test/java/org/apache/camel/component/dapr/DaprConfigurationOptionsProxyTest.java
 
b/components/camel-dapr/src/test/java/org/apache/camel/component/dapr/DaprConfigurationOptionsProxyTest.java
index 1f18a883635d..1ca764ec5e96 100644
--- 
a/components/camel-dapr/src/test/java/org/apache/camel/component/dapr/DaprConfigurationOptionsProxyTest.java
+++ 
b/components/camel-dapr/src/test/java/org/apache/camel/component/dapr/DaprConfigurationOptionsProxyTest.java
@@ -49,4 +49,26 @@ public class DaprConfigurationOptionsProxyTest extends 
CamelTestSupport {
 
         assertNull(configurationOptionsProxy.getMethodToInvoke(exchange));
     }
+
+    @Test
+    void secretStoreAndKeyHeadersApplyToTheSecretOperationOnlyWhenAllowed() {
+        final DaprConfiguration configuration = new DaprConfiguration();
+        configuration.setSecretStore("configStore");
+        configuration.setKey("configKey");
+        final DaprConfigurationOptionsProxy configurationOptionsProxy = new 
DaprConfigurationOptionsProxy(configuration);
+
+        final Exchange exchange = new DefaultExchange(context);
+        exchange.getIn().setHeader(DaprConstants.SECRET_STORE, "headerStore");
+        exchange.getIn().setHeader(DaprConstants.KEY, "headerKey");
+
+        // by default, the secret operation uses the endpoint, and the state 
operations still use the key header
+        assertEquals("configStore", 
configurationOptionsProxy.getSecretStore(exchange));
+        assertEquals("configKey", 
configurationOptionsProxy.getSecretKey(exchange));
+        assertEquals("headerKey", configurationOptionsProxy.getKey(exchange));
+
+        configuration.setAllowSecretStoreAndKeyFromHeaders(true);
+
+        assertEquals("headerStore", 
configurationOptionsProxy.getSecretStore(exchange));
+        assertEquals("headerKey", 
configurationOptionsProxy.getSecretKey(exchange));
+    }
 }
diff --git 
a/components/camel-dapr/src/test/java/org/apache/camel/component/dapr/DaprProducerTest.java
 
b/components/camel-dapr/src/test/java/org/apache/camel/component/dapr/DaprProducerTest.java
index 6397e71a2f0f..06819a118566 100644
--- 
a/components/camel-dapr/src/test/java/org/apache/camel/component/dapr/DaprProducerTest.java
+++ 
b/components/camel-dapr/src/test/java/org/apache/camel/component/dapr/DaprProducerTest.java
@@ -44,10 +44,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -98,6 +100,64 @@ class DaprProducerTest extends CamelTestSupport {
         assertEquals(secrets, exchange.getMessage().getBody());
     }
 
+    @Test
+    void secretStoreAndKeyHeadersAreIgnoredByDefaultForSecret() {
+        Map<String, String> secret = Map.of("mySecret", "myValue");
+        
when(client.getSecret(any(GetSecretRequest.class))).thenReturn(Mono.just(secret));
+
+        Exchange exchange = 
template.request("dapr:secret?secretStore=myStore&key=mySecret&" + CLIENTS, e 
-> {
+            e.getIn().setHeader(DaprConstants.SECRET_STORE, "otherStore");
+            e.getIn().setHeader(DaprConstants.KEY, "otherSecret");
+        });
+
+        assertNull(exchange.getException());
+        ArgumentCaptor<GetSecretRequest> request = 
ArgumentCaptor.forClass(GetSecretRequest.class);
+        verify(client).getSecret(request.capture());
+        assertEquals("myStore", request.getValue().getStoreName());
+        assertEquals("mySecret", request.getValue().getKey());
+    }
+
+    @Test
+    void keyHeaderDoesNotTurnABulkSecretEndpointIntoAnotherSecretByDefault() {
+        Exchange exchange = 
template.request("dapr:secret?secretStore=myStore&" + CLIENTS,
+                e -> e.getIn().setHeader(DaprConstants.KEY, "otherSecret"));
+
+        IllegalArgumentException cause = 
assertInstanceOf(IllegalArgumentException.class, exchange.getException());
+        
assertTrue(cause.getMessage().contains("allowSecretStoreAndKeyFromHeaders=true"));
+        verify(client, never()).getSecret(any(GetSecretRequest.class));
+        verify(client, never()).getBulkSecret(any(GetBulkSecretRequest.class));
+    }
+
+    @Test
+    void secretStoreHeaderDoesNotStandInForAMissingSecretStoreByDefault() {
+        Exchange exchange = template.request("dapr:secret?key=mySecret&" + 
CLIENTS,
+                e -> e.getIn().setHeader(DaprConstants.SECRET_STORE, 
"otherStore"));
+
+        IllegalArgumentException cause = 
assertInstanceOf(IllegalArgumentException.class, exchange.getException());
+        assertTrue(cause.getMessage().contains("secretStore is mandatory"));
+        
assertTrue(cause.getMessage().contains("allowSecretStoreAndKeyFromHeaders=true"));
+        verify(client, never()).getSecret(any(GetSecretRequest.class));
+    }
+
+    @Test
+    void secretStoreAndKeyHeadersOverrideTheEndpointWhenAllowed() {
+        Map<String, String> secret = Map.of("otherSecret", "otherValue");
+        
when(client.getSecret(any(GetSecretRequest.class))).thenReturn(Mono.just(secret));
+
+        Exchange exchange = template.request(
+                
"dapr:secret?secretStore=myStore&allowSecretStoreAndKeyFromHeaders=true&" + 
CLIENTS, e -> {
+                    e.getIn().setHeader(DaprConstants.SECRET_STORE, 
"otherStore");
+                    e.getIn().setHeader(DaprConstants.KEY, "otherSecret");
+                });
+
+        assertNull(exchange.getException());
+        assertEquals(secret, exchange.getMessage().getBody());
+        ArgumentCaptor<GetSecretRequest> request = 
ArgumentCaptor.forClass(GetSecretRequest.class);
+        verify(client).getSecret(request.capture());
+        assertEquals("otherStore", request.getValue().getStoreName());
+        assertEquals("otherSecret", request.getValue().getKey());
+    }
+
     @Test
     void keepsTheHeadersOfTheMessageAndAddsTheResponseHeaders() {
         Map<String, ConfigurationItem> config = Map.of("myKey", new 
ConfigurationItem("myKey", "myValue", "1"));
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 80abc1dfe62c..6df6e7c1d127 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
@@ -71,6 +71,7 @@ public final class SecurityUtils {
         map.put("allowoperationheader", new SecurityOption(INSECURE_DEV, 
"true"));
         map.put("allowpredicatefrommessage", new SecurityOption(INSECURE_DEV, 
"true"));
         map.put("allowqueryfromheader", new SecurityOption(INSECURE_DEV, 
"true"));
+        map.put("allowsecretstoreandkeyfromheaders", new 
SecurityOption(INSECURE_DEV, "true"));
         map.put("allowserializedheaders", new 
SecurityOption(INSECURE_SERIALIZATION, "true"));
         map.put("allowsharedstatefulkey", new SecurityOption(INSECURE_DEV, 
"true"));
         map.put("allowtemplatefromheader", new SecurityOption(INSECURE_DEV, 
"true"));
@@ -154,6 +155,8 @@ public final class SecurityUtils {
                 "component:dynamicroutercontrol"));
         owners.put("allowqueryfromheader", Set.of(
                 "component:sql"));
+        owners.put("allowsecretstoreandkeyfromheaders", Set.of(
+                "component:dapr"));
         owners.put("allowserializedheaders", Set.of(
                 "component:activemq",
                 "component:activemq6",
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index c7fa7e136c87..32dfb74e0991 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -999,6 +999,22 @@ as a quoted, escaped JSON string; a stream body failed. A 
route that relied on t
 it wants, for example with `marshal().json()`. Other bodies, such as a `Map` 
or a POJO, are still serialized as JSON.
 The workflow operations give the body to the workflow client as before.
 
+=== camel-dapr - the secret store and key headers need the 
allowSecretStoreAndKeyFromHeaders option
+
+The `secret` operation of the `dapr` producer took the secret store and the 
key from the `CamelDaprSecretStore` and
+`CamelDaprKey` headers when they were set, over the `secretStore` and `key` 
options of the endpoint, so a message could
+read another secret, or use another secret store, than the endpoint is 
configured with. For the `secret` operation,
+these headers are now ignored unless the endpoint sets the new 
`allowSecretStoreAndKeyFromHeaders=true` option
+(disabled by default), or the component sets 
`camel.component.dapr.allowSecretStoreAndKeyFromHeaders=true`. A route
+that relies on them must set this option.
+
+A `secret` endpoint without a `key`, which took the key from the 
`CamelDaprKey` header, now fails with an error that
+names the option, instead of reading all the secrets of the store. A `secret` 
endpoint without a `secretStore`, which
+took it from the `CamelDaprSecretStore` header, now fails because the secret 
store is missing.
+
+The other operations do not change: the `state` operations still take the key 
from the `CamelDaprKey` header, and the
+other `CamelDapr*` headers still take the place of the options of the 
endpoint, as before.
+
 === camel-consul - no Optional in the body, and the CamelConsulResult header 
of every action
 
 The `GET_SESSIONS` action of `consul:kv`, the `RENEW` action of 
`consul:session` and the `GET` action of
diff --git 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/DaprComponentBuilderFactory.java
 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/DaprComponentBuilderFactory.java
index 577a8863ade8..bc34e319537d 100644
--- 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/DaprComponentBuilderFactory.java
+++ 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/DaprComponentBuilderFactory.java
@@ -719,6 +719,27 @@ public interface DaprComponentBuilderFactory {
             doSetProperty("headerFilterStrategy", headerFilterStrategy);
             return this;
         }
+    
+        
+        /**
+         * Whether to allow overriding the secret store and the key of the
+         * endpoint with the CamelDaprSecretStore and CamelDaprKey headers for
+         * the secret operation. Disabled by default; enable it only when the
+         * header source is trusted, since it lets a message choose the secret
+         * store and the secret that the secret operation reads.
+         * 
+         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param allowSecretStoreAndKeyFromHeaders the value to set
+         * @return the dsl builder
+         */
+        default DaprComponentBuilder allowSecretStoreAndKeyFromHeaders(boolean 
allowSecretStoreAndKeyFromHeaders) {
+            doSetProperty("allowSecretStoreAndKeyFromHeaders", 
allowSecretStoreAndKeyFromHeaders);
+            return this;
+        }
     }
 
     class DaprComponentBuilderImpl
@@ -780,6 +801,7 @@ public interface DaprComponentBuilderFactory {
             case "workflowVersion": getOrCreateConfiguration((DaprComponent) 
component).setWorkflowVersion((java.lang.String) value); return true;
             case "autowiredEnabled": ((DaprComponent) 
component).setAutowiredEnabled((boolean) value); return true;
             case "headerFilterStrategy": ((DaprComponent) 
component).setHeaderFilterStrategy((org.apache.camel.spi.HeaderFilterStrategy) 
value); return true;
+            case "allowSecretStoreAndKeyFromHeaders": 
getOrCreateConfiguration((DaprComponent) 
component).setAllowSecretStoreAndKeyFromHeaders((boolean) value); return true;
             default: return false;
             }
         }
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DaprEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DaprEndpointBuilderFactory.java
index 73c58d0553aa..d5359a55809d 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DaprEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DaprEndpointBuilderFactory.java
@@ -1070,6 +1070,44 @@ public interface DaprEndpointBuilderFactory {
             doSetProperty("workflowVersion", workflowVersion);
             return this;
         }
+        /**
+         * Whether to allow overriding the secret store and the key of the
+         * endpoint with the CamelDaprSecretStore and CamelDaprKey headers for
+         * the secret operation. Disabled by default; enable it only when the
+         * header source is trusted, since it lets a message choose the secret
+         * store and the secret that the secret operation reads.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param allowSecretStoreAndKeyFromHeaders the value to set
+         * @return the dsl builder
+         */
+        default DaprEndpointProducerBuilder 
allowSecretStoreAndKeyFromHeaders(boolean allowSecretStoreAndKeyFromHeaders) {
+            doSetProperty("allowSecretStoreAndKeyFromHeaders", 
allowSecretStoreAndKeyFromHeaders);
+            return this;
+        }
+        /**
+         * Whether to allow overriding the secret store and the key of the
+         * endpoint with the CamelDaprSecretStore and CamelDaprKey headers for
+         * the secret operation. Disabled by default; enable it only when the
+         * header source is trusted, since it lets a message choose the secret
+         * store and the secret that the secret operation reads.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: false
+         * Group: security
+         * 
+         * @param allowSecretStoreAndKeyFromHeaders the value to set
+         * @return the dsl builder
+         */
+        default DaprEndpointProducerBuilder 
allowSecretStoreAndKeyFromHeaders(String allowSecretStoreAndKeyFromHeaders) {
+            doSetProperty("allowSecretStoreAndKeyFromHeaders", 
allowSecretStoreAndKeyFromHeaders);
+            return this;
+        }
     }
 
     /**
@@ -1523,7 +1561,9 @@ public interface DaprEndpointBuilderFactory {
         }
         /**
          * The name of the Dapr secret store to interact with, defined in
-         * local-secret-store.yaml config.
+         * local-secret-store.yaml config. For the secret operation, this 
header
+         * is ignored unless the endpoint enables
+         * allowSecretStoreAndKeyFromHeaders=true (disabled by default).
          * 
          * The option is a: {@code String} type.
          * 
@@ -1549,7 +1589,9 @@ public interface DaprEndpointBuilderFactory {
         }
         /**
          * The key used to identify the state/secret object within the 
specified
-         * state/secret store.
+         * state/secret store. For the secret operation, this header is ignored
+         * unless the endpoint enables allowSecretStoreAndKeyFromHeaders=true
+         * (disabled by default).
          * 
          * The option is a: {@code String} type.
          * 

Reply via email to