Mitigate insecure deserialization in ZookeeperDistributedQueue (CWE-502)#16
Open
devin-ai-integration[bot] wants to merge 2 commits intodevelop-7.0.xfrom
Open
Mitigate insecure deserialization in ZookeeperDistributedQueue (CWE-502)#16devin-ai-integration[bot] wants to merge 2 commits intodevelop-7.0.xfrom
devin-ai-integration[bot] wants to merge 2 commits intodevelop-7.0.xfrom
Conversation
Apply an ObjectInputFilter to ObjectInputStream in ZookeeperDistributedQueue.deserialize() to prevent arbitrary-class deserialization that could lead to RCE if an attacker can influence queue data stored in Zookeeper. The default filter enforces size/depth limits and denies packages that are commonly abused as Java deserialization gadget chains (Commons Collections functors, Groovy, Spring beans factories, Xalan TemplatesImpl, JdbcRowSetImpl, c3p0, Hibernate engine/property, RMI, BeanShell, Clojure, Jython, ROME, Javassist, etc.). Subclasses that store a narrow set of Serializable types should override the new protected getObjectInputFilter() method and return a stricter, allow-list based filter. Co-Authored-By: Arjun Mishra <arjunsaxmishra@gmail.com>
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
The pattern '!org.springframework.core.SerializableTypeWrapper**' was ineffective: JDK ObjectInputFilter only recognizes '.**' (package + subpackages) or '.*' (package only) as wildcard suffixes. A bare '**' falls back to exact-string matching and matches nothing. Switch to a trailing single '*' prefix match so both the outer class and its inner gadget classes (e.g. SerializableTypeWrapper$MethodInvokeTypeProvider) are rejected. Extend the filter test to cover both cases. Co-Authored-By: Arjun Mishra <arjunsaxmishra@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
ZookeeperDistributedQueue.deserialize(byte[])previously calledObjectInputStream.readObject()on bytes read from Zookeeper with no class filtering, which is a CWE-502 insecure deserialization vulnerability. If an attacker can influence data in the Zookeeper znodes backing a queue, they can trigger RCE via known Java deserialization gadget chains.This PR applies a default
ObjectInputFilterto theObjectInputStreamused indeserialize()to block known gadget packages and enforce size/depth limits, and exposes aprotected getObjectInputFilter()hook so subclasses that know their exact payload types can install a stricter allow-list based filter.Changes
ZookeeperDistributedQueue.javaDEFAULT_DESERIALIZATION_FILTER_PATTERN/DEFAULT_DESERIALIZATION_FILTERconstants.protected ObjectInputFilter getObjectInputFilter()method returning the default filter. Subclasses can override.deserialize()now callsois.setObjectInputFilter(...)with whatever the hook returns (unless it returnsnull, which falls back to the JVM-widejdk.serialFilter).ZookeeperDistributedQueueDeserializationFilterTest.javaJdbcRowSetImpl,TemplatesImpl,BadAttributeValueExpException,org.springframework.beans.factory.ObjectFactory) are rejected.org.springframework.core.SerializableTypeWrapperand its inner gadget classSerializableTypeWrapper$MethodInvokeTypeProviderare rejected.Updates since last revision
SerializableTypeWrapperdenylist entry. The original!org.springframework.core.SerializableTypeWrapper**pattern was ineffective — JDKObjectInputFilteronly treats.**(with a leading.) as a package wildcard, so a bare**degenerated to an exact-string match and never fired. Replaced with!org.springframework.core.SerializableTypeWrapper*(trailing single*= class-name prefix match), which covers the outer class and all its inner gadget classes ($MethodInvokeTypeProvider,$TypeProxyInvocationHandler, etc.) without widening the denylist to the entireorg.springframework.corepackage. Caught by Devin Review; verified with an added regression test on the inner class.Labels
Milestone
Upcoming 7.0.x release.
Things To Review Carefully
T extends Serializablemeans callers can legitimately put arbitrary serializable payloads in the queue, the default has to be a denylist for backward compatibility. This is inherently weaker than an allow-list and will not catch future gadget chains. Consumers with a known, narrow payload type should overridegetObjectInputFilter()— please confirm this framework-level trade-off is acceptable, and consider whether any internal subclasses/callers should be switched to an allow-list filter in a follow-up.beans.factory.**andSerializableTypeWrapper*, XalanTemplatesImpl,JdbcRowSetImpl, c3p0, Hibernateengine.spi/property, RMI server, BeanShell, Clojure, Jython/org.python.core, ROME, Javassist, Rhino/org.mozilla.javascript, Vaadin, XBean naming,javax.naming.**). Please sanity-check this list against anything Broadleaf may intentionally put in aZookeeperDistributedQueue— in particularorg.springframework.beans.factory.**andjavax.naming.**are broad and could in theory block legitimate payloads.maxdepth=64,maxarray=1_000_000,maxrefs=100_000,maxbytes=10_000_000. ZK itself limits entries to ~1MB somaxbytes=10MBis comfortably above that, but please confirm these bounds are reasonable for existing queue sizes.deserialize(). Any subclass that already overridesdeserialize()won't pick up this mitigation automatically — they'd need to callgetObjectInputFilter()themselves or upgrade their own implementation.Additional Context
java.io.ObjectInputFilter(Java 9+; this module already targets Java 17 per rootpom.xml).jdk.serialFiltersystem property /conf/security/java.securityfor defense-in-depth.Link to Devin session: https://app.devin.ai/sessions/8fa80316639843f597bd0acfe86747ce
Requested by: @Colhodm