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

oscerd pushed a commit to branch camel-4.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.18.x by this push:
     new e721141ddcae [backport camel-4.18.x] CAMEL-24421: camel-spring-redis - 
apply a deserialization filter to the default JDK serializer (#25589)
e721141ddcae is described below

commit e721141ddcaeb9a08892730942b1b362c2da1c5c
Author: Andrea Cosentino <[email protected]>
AuthorDate: Mon Aug 24 16:57:30 2026 +0200

    [backport camel-4.18.x] CAMEL-24421: camel-spring-redis - apply a 
deserialization filter to the default JDK serializer (#25589)
    
    CAMEL-24421: camel-spring-redis - apply a deserialization filter to the 
default JDK serializer
    
    RedisConfiguration.createDefaultSerializer() built a bare
    JdkSerializationRedisSerializer, whose read path runs through Spring's
    ConfigurableObjectInputStream with no ObjectInputFilter installed. Every 
other
    component in the codebase that performs JDK deserialization -- camel-consul,
    camel-leveldb, camel-mina, camel-netty, camel-netty-http, camel-vertx-http,
    camel-jms, camel-sjms, camel-http-common, camel-cassandraql -- resolves a 
filter
    first, so camel-spring-redis was the one path left without one.
    
    The default serializer now installs a filter resolved through
    DeserializationFilterHelper: the new deserializationFilter option when set,
    otherwise the JVM-wide jdk.serialFilter, otherwise the shared Camel 
allow-list.
    
    JdkSerializationRedisSerializer exposes no hook for a filter, so the 
serializer
    is built through its Converter-based constructor with a deserializing 
converter
    that sets one on the stream. Serialization is left untouched, and class
    resolution is unchanged: the same null class loader Spring's 
DefaultDeserializer
    uses by default is passed through.
    
    This covers the three places that share the default serializer -- the 
consumer,
    which deserializes the payload of every message published to the subscribed
    channels; the producer read commands, through the default RedisTemplate; and
    SpringRedisIdempotentRepository, which builds that same template. Note that
    setting a custom redisTemplate does not reach the consumer, which reads
    getSerializer() directly, so the option covers both paths.
    
    Setting the serializer option to a custom RedisSerializer bypasses the 
filter,
    since Camel then no longer controls how the payload is read.
    
    
    (cherry picked from commit d35b455495bc99afff0266315ff2399c7ff58b30)
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 .../camel/catalog/components/spring-redis.json     |  3 +-
 .../camel-spring-parent/camel-spring-redis/pom.xml |  5 ++
 .../component/redis/RedisEndpointConfigurer.java   |  6 ++
 .../component/redis/RedisEndpointUriFactory.java   |  3 +-
 .../apache/camel/component/redis/spring-redis.json |  3 +-
 .../component/redis/FilteringDeserializer.java     | 80 +++++++++++++++++++
 .../camel/component/redis/RedisConfiguration.java  | 27 ++++++-
 ...edisConfigurationDeserializationFilterTest.java | 91 ++++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_18.adoc    | 21 +++++
 .../endpoint/dsl/RedisEndpointBuilderFactory.java  | 60 ++++++++++++++
 10 files changed, 295 insertions(+), 4 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
index 287abe76920e..85ddfe4508d1 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-redis.json
@@ -72,6 +72,7 @@
     "exceptionHandler": { "index": 8, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
     "exchangePattern": { "index": 9, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
     "listenerContainer": { "index": 10, "kind": "parameter", "displayName": 
"Listener Container", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.springframework.data.redis.listener.RedisMessageListenerContainer", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.redis.RedisConfiguration", "configurationField": 
"configuration", "description": "Reference to a pre-c [...]
-    "lazyStartProducer": { "index": 11, "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 [...]
+    "lazyStartProducer": { "index": 11, "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 [...]
+    "deserializationFilter": { "index": 12, "kind": "parameter", 
"displayName": "Deserialization Filter", "group": "security", "label": 
"advanced,security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.redis.RedisConfiguration", 
"configurationField": "configuration", "description": "Sets an 
ObjectInputFilter pattern (jdk.serialFilter syntax) applied when the [...]
   }
 }
diff --git a/components/camel-spring-parent/camel-spring-redis/pom.xml 
b/components/camel-spring-parent/camel-spring-redis/pom.xml
index 2712ced1193d..8beb6fffb48c 100644
--- a/components/camel-spring-parent/camel-spring-redis/pom.xml
+++ b/components/camel-spring-parent/camel-spring-redis/pom.xml
@@ -62,6 +62,11 @@
             <version>${mockito-version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>jakarta.annotation</groupId>
             <artifactId>jakarta.annotation-api</artifactId>
diff --git 
a/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointConfigurer.java
 
b/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointConfigurer.java
index 6cfe69080332..de09d38e33a4 100644
--- 
a/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointConfigurer.java
+++ 
b/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointConfigurer.java
@@ -29,6 +29,8 @@ public class RedisEndpointConfigurer extends 
PropertyConfigurerSupport implement
         case "command": 
target.getConfiguration().setCommand(property(camelContext, 
org.apache.camel.component.redis.Command.class, value)); return true;
         case "connectionfactory":
         case "connectionFactory": 
target.getConfiguration().setConnectionFactory(property(camelContext, 
org.springframework.data.redis.connection.RedisConnectionFactory.class, 
value)); return true;
+        case "deserializationfilter":
+        case "deserializationFilter": 
target.getConfiguration().setDeserializationFilter(property(camelContext, 
java.lang.String.class, value)); return true;
         case "exceptionhandler":
         case "exceptionHandler": 
target.setExceptionHandler(property(camelContext, 
org.apache.camel.spi.ExceptionHandler.class, value)); return true;
         case "exchangepattern":
@@ -53,6 +55,8 @@ public class RedisEndpointConfigurer extends 
PropertyConfigurerSupport implement
         case "command": return org.apache.camel.component.redis.Command.class;
         case "connectionfactory":
         case "connectionFactory": return 
org.springframework.data.redis.connection.RedisConnectionFactory.class;
+        case "deserializationfilter":
+        case "deserializationFilter": return java.lang.String.class;
         case "exceptionhandler":
         case "exceptionHandler": return 
org.apache.camel.spi.ExceptionHandler.class;
         case "exchangepattern":
@@ -78,6 +82,8 @@ public class RedisEndpointConfigurer extends 
PropertyConfigurerSupport implement
         case "command": return target.getConfiguration().getCommand();
         case "connectionfactory":
         case "connectionFactory": return 
target.getConfiguration().getConnectionFactory();
+        case "deserializationfilter":
+        case "deserializationFilter": return 
target.getConfiguration().getDeserializationFilter();
         case "exceptionhandler":
         case "exceptionHandler": return target.getExceptionHandler();
         case "exchangepattern":
diff --git 
a/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointUriFactory.java
 
b/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointUriFactory.java
index 3df36851f739..d4d9302dfe20 100644
--- 
a/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointUriFactory.java
+++ 
b/components/camel-spring-parent/camel-spring-redis/src/generated/java/org/apache/camel/component/redis/RedisEndpointUriFactory.java
@@ -23,11 +23,12 @@ public class RedisEndpointUriFactory extends 
org.apache.camel.support.component.
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(12);
+        Set<String> props = new HashSet<>(13);
         props.add("bridgeErrorHandler");
         props.add("channels");
         props.add("command");
         props.add("connectionFactory");
+        props.add("deserializationFilter");
         props.add("exceptionHandler");
         props.add("exchangePattern");
         props.add("host");
diff --git 
a/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
 
b/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
index 287abe76920e..85ddfe4508d1 100644
--- 
a/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
+++ 
b/components/camel-spring-parent/camel-spring-redis/src/generated/resources/META-INF/org/apache/camel/component/redis/spring-redis.json
@@ -72,6 +72,7 @@
     "exceptionHandler": { "index": 8, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
     "exchangePattern": { "index": 9, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
     "listenerContainer": { "index": 10, "kind": "parameter", "displayName": 
"Listener Container", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.springframework.data.redis.listener.RedisMessageListenerContainer", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.redis.RedisConfiguration", "configurationField": 
"configuration", "description": "Reference to a pre-c [...]
-    "lazyStartProducer": { "index": 11, "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 [...]
+    "lazyStartProducer": { "index": 11, "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 [...]
+    "deserializationFilter": { "index": 12, "kind": "parameter", 
"displayName": "Deserialization Filter", "group": "security", "label": 
"advanced,security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.redis.RedisConfiguration", 
"configurationField": "configuration", "description": "Sets an 
ObjectInputFilter pattern (jdk.serialFilter syntax) applied when the [...]
   }
 }
diff --git 
a/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/FilteringDeserializer.java
 
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/FilteringDeserializer.java
new file mode 100644
index 000000000000..c25f4ea191ba
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/FilteringDeserializer.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.redis;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.ConfigurableObjectInputStream;
+import org.springframework.core.serializer.Deserializer;
+
+/**
+ * A Spring {@link Deserializer} that installs an {@link ObjectInputFilter} on 
the stream before the object graph is
+ * read.
+ * <p/>
+ * Spring's own {@code DefaultDeserializer} reads through a {@link 
ConfigurableObjectInputStream} without any filter, so
+ * the default {@code JdkSerializationRedisSerializer} would otherwise 
materialise arbitrary types. This deserializer is
+ * behaviourally identical apart from the filter, and in particular resolves 
classes the same way by passing the same
+ * {@code null} class loader that {@code DefaultDeserializer} uses by default.
+ */
+class FilteringDeserializer implements Deserializer<Object> {
+
+    /**
+     * Default {@link ObjectInputFilter} pattern applied when the default JDK 
serializer reads Redis payloads. Allows
+     * standard Java types and Apache Camel types and rejects everything else. 
Can be overridden per-endpoint via
+     * {@link RedisConfiguration#setDeserializationFilter(String)} or globally 
via the JVM system property
+     * {@code jdk.serialFilter}.
+     */
+    static final String DEFAULT_DESERIALIZATION_FILTER
+            = "!java.net.**;java.**;javax.**;org.apache.camel.**;!*";
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(FilteringDeserializer.class);
+
+    private final String deserializationFilter;
+
+    FilteringDeserializer(String deserializationFilter) {
+        this.deserializationFilter = deserializationFilter;
+    }
+
+    @Override
+    public Object deserialize(InputStream inputStream) throws IOException {
+        ObjectInputStream ois = new ConfigurableObjectInputStream(inputStream, 
null);
+        
ois.setObjectInputFilter(resolveDeserializationFilter(deserializationFilter));
+        try {
+            return ois.readObject();
+        } catch (ClassNotFoundException e) {
+            throw new IOException("Failed to deserialize object type", e);
+        }
+    }
+
+    private static ObjectInputFilter resolveDeserializationFilter(String 
configuredPattern) {
+        if (configuredPattern != null && !configuredPattern.isBlank()) {
+            return ObjectInputFilter.Config.createFilter(configuredPattern);
+        }
+        ObjectInputFilter jvmFilter = 
ObjectInputFilter.Config.getSerialFilter();
+        if (jvmFilter != null) {
+            return jvmFilter;
+        }
+        LOG.debug("No JVM-wide deserialization filter set, applying default 
Camel filter: {}",
+                DEFAULT_DESERIALIZATION_FILTER);
+        return 
ObjectInputFilter.Config.createFilter(DEFAULT_DESERIALIZATION_FILTER);
+    }
+}
diff --git 
a/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConfiguration.java
 
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConfiguration.java
index cfb72db8b32d..3c58b2ac5874 100644
--- 
a/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConfiguration.java
+++ 
b/components/camel-spring-parent/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConfiguration.java
@@ -20,6 +20,8 @@ import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriParams;
 import org.apache.camel.spi.UriPath;
+import org.springframework.core.serializer.support.DeserializingConverter;
+import org.springframework.core.serializer.support.SerializingConverter;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
 import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
 import org.springframework.data.redis.core.RedisTemplate;
@@ -50,6 +52,13 @@ public class RedisConfiguration {
     private RedisConnectionFactory connectionFactory;
     @UriParam
     private RedisSerializer<?> serializer;
+    @UriParam(label = "advanced,security",
+              description = "Sets an ObjectInputFilter pattern 
(jdk.serialFilter syntax) applied when the default"
+                            + " JDK serializer deserializes Redis payloads, 
both on the consumer and on producer read"
+                            + " commands. When not set, the JVM-wide 
jdk.serialFilter is used if present; otherwise a"
+                            + " conservative default filter denying java.net.* 
and otherwise allowing java.*, javax.*"
+                            + " and org.apache.camel.* packages is applied. 
Ignored when a custom serializer is set.")
+    private String deserializationFilter;
 
     public Command getCommand() {
         return command;
@@ -141,6 +150,19 @@ public class RedisConfiguration {
         this.serializer = serializer;
     }
 
+    public String getDeserializationFilter() {
+        return deserializationFilter;
+    }
+
+    /**
+     * Sets an {@link java.io.ObjectInputFilter} pattern ({@code 
jdk.serialFilter} syntax) applied when the default JDK
+     * serializer deserializes Redis payloads. When not set, the JVM-wide 
{@code jdk.serialFilter} is used if present,
+     * otherwise a conservative default filter is applied. Ignored when a 
custom serializer is set.
+     */
+    public void setDeserializationFilter(String deserializationFilter) {
+        this.deserializationFilter = deserializationFilter;
+    }
+
     private RedisConnectionFactory createDefaultConnectionFactory() {
         JedisConnectionFactory jedisConnectionFactory = new 
JedisConnectionFactory();
         managedConnectionFactory = true;
@@ -174,7 +196,10 @@ public class RedisConfiguration {
     }
 
     private RedisSerializer<?> createDefaultSerializer() {
-        serializer = new JdkSerializationRedisSerializer();
+        // JdkSerializationRedisSerializer exposes no hook to install an 
ObjectInputFilter, so supply a deserializing
+        // converter that sets one on the stream. Serialization is left 
untouched.
+        serializer = new JdkSerializationRedisSerializer(
+                new SerializingConverter(), new DeserializingConverter(new 
FilteringDeserializer(deserializationFilter)));
         return serializer;
     }
 
diff --git 
a/components/camel-spring-parent/camel-spring-redis/src/test/java/org/apache/camel/component/redis/RedisConfigurationDeserializationFilterTest.java
 
b/components/camel-spring-parent/camel-spring-redis/src/test/java/org/apache/camel/component/redis/RedisConfigurationDeserializationFilterTest.java
new file mode 100644
index 000000000000..29d61fc8b4a4
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-redis/src/test/java/org/apache/camel/component/redis/RedisConfigurationDeserializationFilterTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.redis;
+
+import java.io.InvalidClassException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * The default serializer must not materialise arbitrary types. Redis payloads 
reach {@code RedisConsumer.setBody()} and
+ * the producer read commands straight from the wire, so the deserialization 
filter is what stands between them and
+ * {@code readObject()}.
+ */
+class RedisConfigurationDeserializationFilterTest {
+
+    @SuppressWarnings("unchecked")
+    private static RedisSerializer<Object> serializerOf(RedisConfiguration 
configuration) {
+        return (RedisSerializer<Object>) configuration.getSerializer();
+    }
+
+    @Test
+    void allowedTypeRoundTrips() {
+        RedisSerializer<Object> serializer = serializerOf(new 
RedisConfiguration());
+        List<String> body = new ArrayList<>(List.of("a", "b"));
+
+        
assertThat(serializer.deserialize(serializer.serialize(body))).isEqualTo(body);
+    }
+
+    @Test
+    void deniedJavaNetTypeIsRejected() {
+        RedisSerializer<Object> serializer = serializerOf(new 
RedisConfiguration());
+        byte[] payload = serializer.serialize(URI.create("http://localhost/";));
+
+        assertThatThrownBy(() -> serializer.deserialize(payload))
+                .isInstanceOf(SerializationException.class)
+                .hasRootCauseInstanceOf(InvalidClassException.class);
+    }
+
+    @Test
+    void typeOutsideTheAllowListIsRejected() {
+        RedisSerializer<Object> serializer = serializerOf(new 
RedisConfiguration());
+        // a Serializable type that is not java.*, javax.* or 
org.apache.camel.*, so the trailing !* denies it
+        byte[] payload = serializer.serialize(new 
SerializationException("outside the default allow-list"));
+
+        assertThatThrownBy(() -> serializer.deserialize(payload))
+                .isInstanceOf(SerializationException.class)
+                .hasRootCauseInstanceOf(InvalidClassException.class);
+    }
+
+    @Test
+    void configuredFilterOverridesTheDefault() {
+        RedisConfiguration configuration = new RedisConfiguration();
+        
configuration.setDeserializationFilter("org.springframework.**;java.**;!*");
+        RedisSerializer<Object> serializer = serializerOf(configuration);
+        SerializationException outsideDefaultAllowList = new 
SerializationException("allowed by the custom filter");
+
+        
assertThat(serializer.deserialize(serializer.serialize(outsideDefaultAllowList)))
+                .isInstanceOf(SerializationException.class);
+    }
+
+    @Test
+    void customSerializerIsLeftAlone() {
+        RedisConfiguration configuration = new RedisConfiguration();
+        RedisSerializer<String> custom = RedisSerializer.string();
+        configuration.setSerializer(custom);
+
+        assertThat(configuration.getSerializer()).isSameAs(custom);
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
index 536a60581a21..ed8d9537cfb9 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
@@ -1620,3 +1620,24 @@ that resolve outside the configured directory are 
rejected.
 
 If `downloadFileName` is configured with an expression (i.e. it contains `$`), 
the local
 path is built by that expression as before and is not subject to this check.
+
+=== camel-spring-redis - the default serializer applies a deserialization 
filter
+
+The default serializer, `JdkSerializationRedisSerializer`, now installs a
+`java.io.ObjectInputFilter` while reading Redis payloads. Previously no filter 
was applied at all.
+This affects both the consumer, which deserializes the payload of every 
message published to the
+subscribed channels, and the producer read commands, which deserialize the 
values stored in Redis.
+
+When no explicit pattern is configured, the JVM-wide `jdk.serialFilter` is 
honoured if set,
+otherwise a conservative default allow-list is applied (it permits standard 
Java and Apache Camel
+types and denies `java.net.**`). Routes that exchange classes outside that 
allow-list must widen it
+through the new `deserializationFilter` endpoint option, for example:
+
+[source,java]
+----
+from("spring-redis://localhost:6379?command=SUBSCRIBE&channels=myChannel"
+     + "&deserializationFilter=com.example.model.**;java.**;!*")
+----
+
+Setting the `serializer` option to a custom `RedisSerializer` bypasses the 
filter entirely, since
+Camel then no longer controls how the payload is read.
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RedisEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RedisEndpointBuilderFactory.java
index 5771468dcfdc..f00f4607bc80 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RedisEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RedisEndpointBuilderFactory.java
@@ -344,6 +344,26 @@ public interface RedisEndpointBuilderFactory {
             doSetProperty("listenerContainer", listenerContainer);
             return this;
         }
+        /**
+         * Sets an ObjectInputFilter pattern (jdk.serialFilter syntax) applied
+         * when the default JDK serializer deserializes Redis payloads, both on
+         * the consumer and on producer read commands. When not set, the
+         * JVM-wide jdk.serialFilter is used if present; otherwise a
+         * conservative default filter denying java.net. and otherwise allowing
+         * java., javax. and org.apache.camel. packages is applied. Ignored 
when
+         * a custom serializer is set.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: security
+         * 
+         * @param deserializationFilter the value to set
+         * @return the dsl builder
+         */
+        default AdvancedRedisEndpointConsumerBuilder 
deserializationFilter(String deserializationFilter) {
+            doSetProperty("deserializationFilter", deserializationFilter);
+            return this;
+        }
     }
 
     /**
@@ -553,6 +573,26 @@ public interface RedisEndpointBuilderFactory {
             doSetProperty("lazyStartProducer", lazyStartProducer);
             return this;
         }
+        /**
+         * Sets an ObjectInputFilter pattern (jdk.serialFilter syntax) applied
+         * when the default JDK serializer deserializes Redis payloads, both on
+         * the consumer and on producer read commands. When not set, the
+         * JVM-wide jdk.serialFilter is used if present; otherwise a
+         * conservative default filter denying java.net. and otherwise allowing
+         * java., javax. and org.apache.camel. packages is applied. Ignored 
when
+         * a custom serializer is set.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: security
+         * 
+         * @param deserializationFilter the value to set
+         * @return the dsl builder
+         */
+        default AdvancedRedisEndpointProducerBuilder 
deserializationFilter(String deserializationFilter) {
+            doSetProperty("deserializationFilter", deserializationFilter);
+            return this;
+        }
     }
 
     /**
@@ -720,6 +760,26 @@ public interface RedisEndpointBuilderFactory {
             return (RedisEndpointBuilder) this;
         }
 
+        /**
+         * Sets an ObjectInputFilter pattern (jdk.serialFilter syntax) applied
+         * when the default JDK serializer deserializes Redis payloads, both on
+         * the consumer and on producer read commands. When not set, the
+         * JVM-wide jdk.serialFilter is used if present; otherwise a
+         * conservative default filter denying java.net. and otherwise allowing
+         * java., javax. and org.apache.camel. packages is applied. Ignored 
when
+         * a custom serializer is set.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: security
+         * 
+         * @param deserializationFilter the value to set
+         * @return the dsl builder
+         */
+        default AdvancedRedisEndpointBuilder deserializationFilter(String 
deserializationFilter) {
+            doSetProperty("deserializationFilter", deserializationFilter);
+            return this;
+        }
     }
 
     public interface RedisBuilders {

Reply via email to