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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 85ac83ef56c6 CAMEL-24296: camel-support - apply a JEP-290 
deserialization filter on CamelObjectInputStream by default
85ac83ef56c6 is described below

commit 85ac83ef56c64b45e1f2dc7debee3866a8b03e39
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Aug 6 15:38:58 2026 +0200

    CAMEL-24296: camel-support - apply a JEP-290 deserialization filter on 
CamelObjectInputStream by default
    
    CamelObjectInputStream now installs a JEP-290 ObjectInputFilter by default 
as a
    defense-in-depth measure against unsafe deserialization. When no explicit 
filter
    pattern is supplied, the JVM-wide jdk.serialFilter is honoured if set, 
otherwise
    Camel's default allow-list is applied.
    
    HttpHelper updated to use the new 3-arg constructor. Upgrade guide entry 
added.
    
    Closes #25378
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 .../org/apache/camel/http/common/HttpHelper.java   |  3 +-
 .../camel/support/CamelObjectInputStream.java      | 27 ++++++++
 .../camel/support/CamelObjectInputStreamTest.java  | 78 ++++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_22.adoc    | 15 +++++
 4 files changed, 121 insertions(+), 2 deletions(-)

diff --git 
a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpHelper.java
 
b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpHelper.java
index a95af16da5f0..93195b91d95b 100644
--- 
a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpHelper.java
+++ 
b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpHelper.java
@@ -142,8 +142,7 @@ public final class HttpHelper {
         }
 
         Object answer;
-        ObjectInputStream ois = new CamelObjectInputStream(is, context);
-        
ois.setObjectInputFilter(DeserializationFilterHelper.resolveDeserializationFilter(deserializationFilter));
+        ObjectInputStream ois = new CamelObjectInputStream(is, context, 
deserializationFilter);
         try {
             answer = ois.readObject();
         } finally {
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/CamelObjectInputStream.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/CamelObjectInputStream.java
index 927160ed3a8a..c87041491901 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/CamelObjectInputStream.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/CamelObjectInputStream.java
@@ -18,21 +18,48 @@ package org.apache.camel.support;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.ObjectInputFilter;
 import java.io.ObjectInputStream;
 import java.io.ObjectStreamClass;
 
 import org.apache.camel.CamelContext;
 
+/**
+ * An {@link ObjectInputStream} that resolves classes against the Camel 
application classloader and installs a JEP-290
+ * {@link ObjectInputFilter} while reading, as a defense-in-depth measure 
against unsafe deserialization.
+ *
+ * <p>
+ * As this is the shared stream used by Camel deserialization consumers, the 
filter is applied by default so that every
+ * caller inherits it. When no explicit pattern is supplied the JVM-wide 
{@code jdk.serialFilter} is honoured if set,
+ * otherwise {@link 
DeserializationFilterHelper#DEFAULT_DESERIALIZATION_FILTER} is applied.
+ */
 public class CamelObjectInputStream extends ObjectInputStream {
     private final ClassLoader classLoader;
 
     public CamelObjectInputStream(InputStream in, CamelContext context) throws 
IOException {
+        this(in, context, null);
+    }
+
+    /**
+     * Creates a {@link CamelObjectInputStream} that applies a JEP-290 {@link 
ObjectInputFilter} while reading.
+     *
+     * @param  in                    the input stream to read from
+     * @param  context               the camel context used to resolve the 
application classloader; may be {@code null}
+     * @param  deserializationFilter an {@link ObjectInputFilter} pattern 
(same syntax as {@code jdk.serialFilter}) to
+     *                               apply; when {@code null} or blank the 
JVM-wide {@code jdk.serialFilter} is used if
+     *                               present, otherwise
+     *                               {@link 
DeserializationFilterHelper#DEFAULT_DESERIALIZATION_FILTER} is applied
+     * @throws IOException           if an I/O error occurs while reading the 
stream header
+     * @since                        4.22
+     */
+    public CamelObjectInputStream(InputStream in, CamelContext context, String 
deserializationFilter) throws IOException {
         super(in);
         if (context != null) {
             this.classLoader = context.getApplicationContextClassLoader();
         } else {
             this.classLoader = null;
         }
+        
setObjectInputFilter(DeserializationFilterHelper.resolveDeserializationFilter(deserializationFilter));
     }
 
     @Override
diff --git 
a/core/camel-support/src/test/java/org/apache/camel/support/CamelObjectInputStreamTest.java
 
b/core/camel-support/src/test/java/org/apache/camel/support/CamelObjectInputStreamTest.java
new file mode 100644
index 000000000000..bcbf8095dcd0
--- /dev/null
+++ 
b/core/camel-support/src/test/java/org/apache/camel/support/CamelObjectInputStreamTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.support;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectOutputStream;
+import java.net.InetSocketAddress;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CamelObjectInputStreamTest {
+
+    @Test
+    void defaultFilterAllowsStandardTypes() throws Exception {
+        assertEquals("hello camel", deserialize(serialize("hello camel")));
+    }
+
+    @Test
+    void defaultFilterRejectsClassOutsideAllowList() throws Exception {
+        byte[] data = 
serialize(InetSocketAddress.createUnresolved("example.com", 8080));
+        InvalidClassException ex = assertThrows(InvalidClassException.class, 
() -> deserialize(data));
+        assertTrue(ex.getMessage().contains("REJECTED"), ex.getMessage());
+    }
+
+    @Test
+    void blankFilterFallsBackToDefault() throws Exception {
+        byte[] data = 
serialize(InetSocketAddress.createUnresolved("example.com", 8080));
+        InvalidClassException ex = assertThrows(InvalidClassException.class, 
() -> deserialize(data, "   "));
+        assertTrue(ex.getMessage().contains("REJECTED"), ex.getMessage());
+    }
+
+    @Test
+    void explicitFilterCanAllowOtherwiseDeniedClass() throws Exception {
+        InetSocketAddress address = 
InetSocketAddress.createUnresolved("example.com", 8080);
+        assertEquals(address, deserialize(serialize(address), "java.**;!*"));
+    }
+
+    private static byte[] serialize(Object value) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+            oos.writeObject(value);
+        }
+        return bos.toByteArray();
+    }
+
+    private static Object deserialize(byte[] data) throws IOException, 
ClassNotFoundException {
+        try (CamelObjectInputStream ois = new CamelObjectInputStream(new 
ByteArrayInputStream(data), null)) {
+            return ois.readObject();
+        }
+    }
+
+    private static Object deserialize(byte[] data, String filter) throws 
IOException, ClassNotFoundException {
+        try (CamelObjectInputStream ois = new CamelObjectInputStream(new 
ByteArrayInputStream(data), null, filter)) {
+            return ois.readObject();
+        }
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
index c79eee332eb9..f4a459dd7e75 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
@@ -55,6 +55,21 @@ recipient; aligning it with `toD` / `enrich` is deferred to 
a follow-up.
 If you need a placeholder resolved by `toD` / `enrich`, keep it in the route's 
endpoint URI rather
 than in the message.
 
+=== camel-support - CamelObjectInputStream applies a deserialization filter by 
default
+
+`CamelObjectInputStream` (the shared stream used by Camel's Java-object 
deserialization paths, such
+as the HTTP components) now installs a JEP-290 `java.io.ObjectInputFilter` 
while reading, as a
+defense-in-depth measure against unsafe deserialization. When no explicit 
filter pattern is
+supplied, the JVM-wide `jdk.serialFilter` is honoured if set, otherwise 
Camel's default allow-list
+(`DeserializationFilterHelper.DEFAULT_DESERIALIZATION_FILTER`) is applied, 
which permits standard
+Java and Apache Camel types, denies `java.net.**`, and enforces graph-shape 
limits.
+
+The built-in HTTP deserialization path already applied this filter, so most 
users are unaffected.
+Code that constructs `CamelObjectInputStream` directly and deserializes types 
outside the default
+allow-list must pass an explicit filter pattern to the new
+`CamelObjectInputStream(InputStream, CamelContext, String)` constructor (or 
configure
+`jdk.serialFilter`) to permit them.
+
 === camel-jbang
 
 The Camel JBang CLI (Camel CLI) and TUI have been promoted from _Preview_ to 
_Stable_ support level.

Reply via email to