VYPR
High severity8.8NVD Advisory· Published Apr 27, 2026· Updated Apr 28, 2026

CVE-2026-27172

CVE-2026-27172

Description

The ConsulRegistry in the camel-consul component (class org.apache.camel.component.consul.ConsulRegistry and its inner ConsulRegistryUtils.deserialize method) read Java-serialized values from the Consul KV store and passed them to ObjectInputStream.readObject() without configuring an ObjectInputFilter. An attacker who can write to the Consul KV store backing a Camel ConsulRegistry instance could inject a malicious serialized Java object that is deserialized the next time Camel performs a lookup against that registry, leading to arbitrary code execution in the Camel process. The issue mirrors the class of vulnerability already addressed for other Camel components in CVE-2024-22369, CVE-2024-23114 and CVE-2026-25747, and was overlooked during the original remediation of those CVEs.

This issue affects Apache Camel: from 3.0.0 before 4.14.6, from 4.15.0 before 4.18.1.

Users are recommended to upgrade to version 4.19.0, which fixes the issue. If users are on the 4.14.x LTS releases stream, then they are suggested to upgrade to 4.14.6. If users are on the 4.18.x releases stream, then they are suggested to upgrade to 4.18.1.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.camel:camel-consulMaven
>= 3.0.0, < 4.14.64.14.6
org.apache.camel:camel-consulMaven
>= 4.15.0, < 4.18.14.18.1

Affected products

1
  • cpe:2.3:a:apache:camel:*:*:*:*:*:*:*:*
    Range: >=3.0.0,<4.14.6

Patches

3
4b540e6e20ba

CAMEL-23029 - Camel-Consul: Add ObjectInputFilter String pattern parameter in ConsulRegistry to be used in deserialize operations (#21532)

https://github.com/apache/camelAndrea CosentinoFeb 18, 2026via ghsa
2 files changed · +45 11
  • components/camel-consul/src/main/java/org/apache/camel/component/consul/ConsulRegistry.java+42 9 modified
    @@ -19,6 +19,7 @@
     import java.io.ByteArrayInputStream;
     import java.io.ByteArrayOutputStream;
     import java.io.IOException;
    +import java.io.ObjectInputFilter;
     import java.io.ObjectInputStream;
     import java.io.ObjectOutputStream;
     import java.io.Serializable;
    @@ -52,6 +53,7 @@ public class ConsulRegistry implements Registry {
         private int port = 8500;
         private Consul consul;
         private KeyValueClient kvClient;
    +    private String deserializationFilter = "java.**;org.apache.camel.**;!*";
     
         /* constructor with default port */
         public ConsulRegistry(String hostname) {
    @@ -70,6 +72,9 @@ private ConsulRegistry(Builder builder) {
             this.hostname = builder.hostname;
             this.port = builder.port;
             this.consul = Consul.builder().withUrl("http://" + this.hostname + ":" + this.port).build();
    +        if (builder.deserializationFilter != null) {
    +            this.deserializationFilter = builder.deserializationFilter;
    +        }
         }
     
         @Override
    @@ -80,7 +85,7 @@ public Object lookupByName(String key) {
     
             return kvClient.getValueAsString(key).map(result -> {
                 byte[] postDecodedValue = ConsulRegistryUtils.decodeBase64(result);
    -            return ConsulRegistryUtils.deserialize(postDecodedValue);
    +            return ConsulRegistryUtils.deserialize(postDecodedValue, deserializationFilter);
             }).orElse(null);
         }
     
    @@ -219,7 +224,7 @@ public void put(String key, Object object) {
             if (lookupByName(key) != null) {
                 remove(key);
             }
    -        Object clone = ConsulRegistryUtils.clone((Serializable) object);
    +        Object clone = ConsulRegistryUtils.clone((Serializable) object, deserializationFilter);
             byte[] serializedObject = ConsulRegistryUtils.serialize((Serializable) clone);
             // pre-encode due native encoding issues
             String value = ConsulRegistryUtils.encodeBase64(serializedObject);
    @@ -235,6 +240,7 @@ public static class Builder {
             String hostname;
             // optional parameter
             Integer port = 8500;
    +        String deserializationFilter;
     
             public Builder(String hostname) {
                 this.hostname = hostname;
    @@ -245,6 +251,11 @@ public Builder port(Integer port) {
                 return this;
             }
     
    +        public Builder deserializationFilter(String deserializationFilter) {
    +            this.deserializationFilter = deserializationFilter;
    +            return this;
    +        }
    +
             public ConsulRegistry build() {
                 return new ConsulRegistry(this);
             }
    @@ -266,6 +277,23 @@ public void setPort(int port) {
             this.port = port;
         }
     
    +    /**
    +     * Gets the deserialization filter applied when reading objects from Consul KV store.
    +     */
    +    public String getDeserializationFilter() {
    +        return deserializationFilter;
    +    }
    +
    +    /**
    +     * Sets a deserialization filter while reading objects from Consul KV store. By default the filter will allow all
    +     * java packages and subpackages and all org.apache.camel packages and subpackages, while the remaining will be
    +     * blacklisted and not deserialized. This parameter should be customized if you're using classes you trust to be
    +     * deserialized.
    +     */
    +    public void setDeserializationFilter(String deserializationFilter) {
    +        this.deserializationFilter = deserializationFilter;
    +    }
    +
         static final class ConsulRegistryUtils {
     
             private ConsulRegistryUtils() {
    @@ -296,11 +324,15 @@ static String encodeBase64(final byte[] binaryData) {
             /**
              * Deserializes an object out of the given byte array.
              *
    -         * @param  bytes the byte array to deserialize from
    -         * @return       an {@link Object} deserialized from the given byte array
    +         * @param  bytes                 the byte array to deserialize from
    +         * @param  deserializationFilter the deserialization filter to apply (e.g. "java.**;org.apache.camel.**;!*")
    +         * @return                       an {@link Object} deserialized from the given byte array
              */
    -        static Object deserialize(byte[] bytes) {
    +        static Object deserialize(byte[] bytes, String deserializationFilter) {
                 try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
    +                if (deserializationFilter != null && !deserializationFilter.isEmpty()) {
    +                    in.setObjectInputFilter(ObjectInputFilter.Config.createFilter(deserializationFilter));
    +                }
                     return in.readObject();
                 } catch (IOException | ClassNotFoundException e) {
                     throw new RuntimeCamelException(e);
    @@ -310,11 +342,12 @@ static Object deserialize(byte[] bytes) {
             /**
              * A deep serialization based clone
              *
    -         * @param  object the object to clone
    -         * @return        a deep clone
    +         * @param  object                the object to clone
    +         * @param  deserializationFilter the deserialization filter to apply
    +         * @return                       a deep clone
              */
    -        static Object clone(Serializable object) {
    -            return deserialize(serialize(object));
    +        static Object clone(Serializable object, String deserializationFilter) {
    +            return deserialize(serialize(object), deserializationFilter);
             }
     
             /**
    
  • components/camel-consul/src/test/java/org/apache/camel/component/consul/ConsulRegistryUtilsTest.java+3 2 modified
    @@ -33,9 +33,10 @@ public class ConsulRegistryUtilsTest {
     
         @Test
         public void encodeDecode() {
    +        final String filter = "java.**;org.apache.camel.**;!*";
             final List<String> src = Arrays.asList("one", "\u0434\u0432\u0430", "t\u0159i");
             final byte[] serialized = ConsulRegistryUtils.serialize((Serializable) src);
    -        assertEquals(src, ConsulRegistryUtils.deserialize(serialized));
    +        assertEquals(src, ConsulRegistryUtils.deserialize(serialized, filter));
             final String encoded = ConsulRegistryUtils.encodeBase64(serialized);
             assertEquals("rO0ABXNyABpqYXZhLnV0aWwuQXJyYXlzJEFycmF5TGlzdNmkPL7NiAbSAgABWwABYXQAE1tMamF2YS9sYW5nL09iamVjdDt4"
                          + "cHVyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAN0AANvbmV0AAbQtNCy0LB0AAR0xZlp",
    @@ -53,7 +54,7 @@ public void encodeDecode() {
                             -48, -76, -48, -78, -48, -80, 116, 0,
                             4, 116, -59, -103, 105 },
                     decoded);
    -        assertEquals(src, ConsulRegistryUtils.deserialize(decoded));
    +        assertEquals(src, ConsulRegistryUtils.deserialize(decoded, filter));
         }
     
     }
    
55dd9f8ce5f6

CAMEL-23029 - Camel-Consul: Add ObjectInputFilter String pattern parameter in ConsulRegistry to be used in deserialize operations (#21530)

https://github.com/apache/camelAndrea CosentinoFeb 18, 2026via ghsa
2 files changed · +45 11
  • components/camel-consul/src/main/java/org/apache/camel/component/consul/ConsulRegistry.java+42 9 modified
    @@ -19,6 +19,7 @@
     import java.io.ByteArrayInputStream;
     import java.io.ByteArrayOutputStream;
     import java.io.IOException;
    +import java.io.ObjectInputFilter;
     import java.io.ObjectInputStream;
     import java.io.ObjectOutputStream;
     import java.io.Serializable;
    @@ -52,6 +53,7 @@ public class ConsulRegistry implements Registry {
         private int port = 8500;
         private Consul consul;
         private KeyValueClient kvClient;
    +    private String deserializationFilter = "java.**;org.apache.camel.**;!*";
     
         /* constructor with default port */
         public ConsulRegistry(String hostname) {
    @@ -70,6 +72,9 @@ private ConsulRegistry(Builder builder) {
             this.hostname = builder.hostname;
             this.port = builder.port;
             this.consul = Consul.builder().withUrl("http://" + this.hostname + ":" + this.port).build();
    +        if (builder.deserializationFilter != null) {
    +            this.deserializationFilter = builder.deserializationFilter;
    +        }
         }
     
         @Override
    @@ -80,7 +85,7 @@ public Object lookupByName(String key) {
     
             return kvClient.getValueAsString(key).map(result -> {
                 byte[] postDecodedValue = ConsulRegistryUtils.decodeBase64(result);
    -            return ConsulRegistryUtils.deserialize(postDecodedValue);
    +            return ConsulRegistryUtils.deserialize(postDecodedValue, deserializationFilter);
             }).orElse(null);
         }
     
    @@ -219,7 +224,7 @@ public void put(String key, Object object) {
             if (lookupByName(key) != null) {
                 remove(key);
             }
    -        Object clone = ConsulRegistryUtils.clone((Serializable) object);
    +        Object clone = ConsulRegistryUtils.clone((Serializable) object, deserializationFilter);
             byte[] serializedObject = ConsulRegistryUtils.serialize((Serializable) clone);
             // pre-encode due native encoding issues
             String value = ConsulRegistryUtils.encodeBase64(serializedObject);
    @@ -239,6 +244,7 @@ public static class Builder {
             String hostname;
             // optional parameter
             Integer port = 8500;
    +        String deserializationFilter;
     
             public Builder(String hostname) {
                 this.hostname = hostname;
    @@ -249,6 +255,11 @@ public Builder port(Integer port) {
                 return this;
             }
     
    +        public Builder deserializationFilter(String deserializationFilter) {
    +            this.deserializationFilter = deserializationFilter;
    +            return this;
    +        }
    +
             public ConsulRegistry build() {
                 return new ConsulRegistry(this);
             }
    @@ -270,6 +281,23 @@ public void setPort(int port) {
             this.port = port;
         }
     
    +    /**
    +     * Gets the deserialization filter applied when reading objects from Consul KV store.
    +     */
    +    public String getDeserializationFilter() {
    +        return deserializationFilter;
    +    }
    +
    +    /**
    +     * Sets a deserialization filter while reading objects from Consul KV store. By default the filter will allow all
    +     * java packages and subpackages and all org.apache.camel packages and subpackages, while the remaining will be
    +     * blacklisted and not deserialized. This parameter should be customized if you're using classes you trust to be
    +     * deserialized.
    +     */
    +    public void setDeserializationFilter(String deserializationFilter) {
    +        this.deserializationFilter = deserializationFilter;
    +    }
    +
         static final class ConsulRegistryUtils {
     
             private ConsulRegistryUtils() {
    @@ -300,11 +328,15 @@ static String encodeBase64(final byte[] binaryData) {
             /**
              * Deserializes an object out of the given byte array.
              *
    -         * @param  bytes the byte array to deserialize from
    -         * @return       an {@link Object} deserialized from the given byte array
    +         * @param  bytes                 the byte array to deserialize from
    +         * @param  deserializationFilter the deserialization filter to apply (e.g. "java.**;org.apache.camel.**;!*")
    +         * @return                       an {@link Object} deserialized from the given byte array
              */
    -        static Object deserialize(byte[] bytes) {
    +        static Object deserialize(byte[] bytes, String deserializationFilter) {
                 try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
    +                if (deserializationFilter != null && !deserializationFilter.isEmpty()) {
    +                    in.setObjectInputFilter(ObjectInputFilter.Config.createFilter(deserializationFilter));
    +                }
                     return in.readObject();
                 } catch (IOException | ClassNotFoundException e) {
                     throw new RuntimeCamelException(e);
    @@ -314,11 +346,12 @@ static Object deserialize(byte[] bytes) {
             /**
              * A deep serialization based clone
              *
    -         * @param  object the object to clone
    -         * @return        a deep clone
    +         * @param  object                the object to clone
    +         * @param  deserializationFilter the deserialization filter to apply
    +         * @return                       a deep clone
              */
    -        static Object clone(Serializable object) {
    -            return deserialize(serialize(object));
    +        static Object clone(Serializable object, String deserializationFilter) {
    +            return deserialize(serialize(object), deserializationFilter);
             }
     
             /**
    
  • components/camel-consul/src/test/java/org/apache/camel/component/consul/ConsulRegistryUtilsTest.java+3 2 modified
    @@ -33,9 +33,10 @@ public class ConsulRegistryUtilsTest {
     
         @Test
         public void encodeDecode() {
    +        final String filter = "java.**;org.apache.camel.**;!*";
             final List<String> src = Arrays.asList("one", "\u0434\u0432\u0430", "t\u0159i");
             final byte[] serialized = ConsulRegistryUtils.serialize((Serializable) src);
    -        assertEquals(src, ConsulRegistryUtils.deserialize(serialized));
    +        assertEquals(src, ConsulRegistryUtils.deserialize(serialized, filter));
             final String encoded = ConsulRegistryUtils.encodeBase64(serialized);
             assertEquals("rO0ABXNyABpqYXZhLnV0aWwuQXJyYXlzJEFycmF5TGlzdNmkPL7NiAbSAgABWwABYXQAE1tMamF2YS9sYW5nL09iamVjdDt4"
                          + "cHVyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAN0AANvbmV0AAbQtNCy0LB0AAR0xZlp",
    @@ -53,7 +54,7 @@ public void encodeDecode() {
                             -48, -76, -48, -78, -48, -80, 116, 0,
                             4, 116, -59, -103, 105 },
                     decoded);
    -        assertEquals(src, ConsulRegistryUtils.deserialize(decoded));
    +        assertEquals(src, ConsulRegistryUtils.deserialize(decoded, filter));
         }
     
     }
    
4e3f709b97ae

CAMEL-23029 - Camel-Consul: Add ObjectInputFilter String pattern parameter in ConsulRegistry to be used in deserialize operations (#21531)

https://github.com/apache/camelAndrea CosentinoFeb 18, 2026via ghsa
2 files changed · +45 11
  • components/camel-consul/src/main/java/org/apache/camel/component/consul/ConsulRegistry.java+42 9 modified
    @@ -19,6 +19,7 @@
     import java.io.ByteArrayInputStream;
     import java.io.ByteArrayOutputStream;
     import java.io.IOException;
    +import java.io.ObjectInputFilter;
     import java.io.ObjectInputStream;
     import java.io.ObjectOutputStream;
     import java.io.Serializable;
    @@ -52,6 +53,7 @@ public class ConsulRegistry implements Registry {
         private int port = 8500;
         private Consul consul;
         private KeyValueClient kvClient;
    +    private String deserializationFilter = "java.**;org.apache.camel.**;!*";
     
         /* constructor with default port */
         public ConsulRegistry(String hostname) {
    @@ -70,6 +72,9 @@ private ConsulRegistry(Builder builder) {
             this.hostname = builder.hostname;
             this.port = builder.port;
             this.consul = Consul.builder().withUrl("http://" + this.hostname + ":" + this.port).build();
    +        if (builder.deserializationFilter != null) {
    +            this.deserializationFilter = builder.deserializationFilter;
    +        }
         }
     
         @Override
    @@ -80,7 +85,7 @@ public Object lookupByName(String key) {
     
             return kvClient.getValueAsString(key).map(result -> {
                 byte[] postDecodedValue = ConsulRegistryUtils.decodeBase64(result);
    -            return ConsulRegistryUtils.deserialize(postDecodedValue);
    +            return ConsulRegistryUtils.deserialize(postDecodedValue, deserializationFilter);
             }).orElse(null);
         }
     
    @@ -219,7 +224,7 @@ public void put(String key, Object object) {
             if (lookupByName(key) != null) {
                 remove(key);
             }
    -        Object clone = ConsulRegistryUtils.clone((Serializable) object);
    +        Object clone = ConsulRegistryUtils.clone((Serializable) object, deserializationFilter);
             byte[] serializedObject = ConsulRegistryUtils.serialize((Serializable) clone);
             // pre-encode due native encoding issues
             String value = ConsulRegistryUtils.encodeBase64(serializedObject);
    @@ -239,6 +244,7 @@ public static class Builder {
             String hostname;
             // optional parameter
             Integer port = 8500;
    +        String deserializationFilter;
     
             public Builder(String hostname) {
                 this.hostname = hostname;
    @@ -249,6 +255,11 @@ public Builder port(Integer port) {
                 return this;
             }
     
    +        public Builder deserializationFilter(String deserializationFilter) {
    +            this.deserializationFilter = deserializationFilter;
    +            return this;
    +        }
    +
             public ConsulRegistry build() {
                 return new ConsulRegistry(this);
             }
    @@ -270,6 +281,23 @@ public void setPort(int port) {
             this.port = port;
         }
     
    +    /**
    +     * Gets the deserialization filter applied when reading objects from Consul KV store.
    +     */
    +    public String getDeserializationFilter() {
    +        return deserializationFilter;
    +    }
    +
    +    /**
    +     * Sets a deserialization filter while reading objects from Consul KV store. By default the filter will allow all
    +     * java packages and subpackages and all org.apache.camel packages and subpackages, while the remaining will be
    +     * blacklisted and not deserialized. This parameter should be customized if you're using classes you trust to be
    +     * deserialized.
    +     */
    +    public void setDeserializationFilter(String deserializationFilter) {
    +        this.deserializationFilter = deserializationFilter;
    +    }
    +
         static final class ConsulRegistryUtils {
     
             private ConsulRegistryUtils() {
    @@ -300,11 +328,15 @@ static String encodeBase64(final byte[] binaryData) {
             /**
              * Deserializes an object out of the given byte array.
              *
    -         * @param  bytes the byte array to deserialize from
    -         * @return       an {@link Object} deserialized from the given byte array
    +         * @param  bytes                 the byte array to deserialize from
    +         * @param  deserializationFilter the deserialization filter to apply (e.g. "java.**;org.apache.camel.**;!*")
    +         * @return                       an {@link Object} deserialized from the given byte array
              */
    -        static Object deserialize(byte[] bytes) {
    +        static Object deserialize(byte[] bytes, String deserializationFilter) {
                 try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
    +                if (deserializationFilter != null && !deserializationFilter.isEmpty()) {
    +                    in.setObjectInputFilter(ObjectInputFilter.Config.createFilter(deserializationFilter));
    +                }
                     return in.readObject();
                 } catch (IOException | ClassNotFoundException e) {
                     throw new RuntimeCamelException(e);
    @@ -314,11 +346,12 @@ static Object deserialize(byte[] bytes) {
             /**
              * A deep serialization based clone
              *
    -         * @param  object the object to clone
    -         * @return        a deep clone
    +         * @param  object                the object to clone
    +         * @param  deserializationFilter the deserialization filter to apply
    +         * @return                       a deep clone
              */
    -        static Object clone(Serializable object) {
    -            return deserialize(serialize(object));
    +        static Object clone(Serializable object, String deserializationFilter) {
    +            return deserialize(serialize(object), deserializationFilter);
             }
     
             /**
    
  • components/camel-consul/src/test/java/org/apache/camel/component/consul/ConsulRegistryUtilsTest.java+3 2 modified
    @@ -33,9 +33,10 @@ public class ConsulRegistryUtilsTest {
     
         @Test
         public void encodeDecode() {
    +        final String filter = "java.**;org.apache.camel.**;!*";
             final List<String> src = Arrays.asList("one", "\u0434\u0432\u0430", "t\u0159i");
             final byte[] serialized = ConsulRegistryUtils.serialize((Serializable) src);
    -        assertEquals(src, ConsulRegistryUtils.deserialize(serialized));
    +        assertEquals(src, ConsulRegistryUtils.deserialize(serialized, filter));
             final String encoded = ConsulRegistryUtils.encodeBase64(serialized);
             assertEquals("rO0ABXNyABpqYXZhLnV0aWwuQXJyYXlzJEFycmF5TGlzdNmkPL7NiAbSAgABWwABYXQAE1tMamF2YS9sYW5nL09iamVjdDt4"
                          + "cHVyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAN0AANvbmV0AAbQtNCy0LB0AAR0xZlp",
    @@ -53,7 +54,7 @@ public void encodeDecode() {
                             -48, -76, -48, -78, -48, -80, 116, 0,
                             4, 116, -59, -103, 105 },
                     decoded);
    -        assertEquals(src, ConsulRegistryUtils.deserialize(decoded));
    +        assertEquals(src, ConsulRegistryUtils.deserialize(decoded, filter));
         }
     
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.