Insecure Deserialization: Definition, Risks, and Prevention
Most application security focuses on what you write. Insecure deserialization exploits what your code loads. An attacker sends a serialized object that reconstructs into a gadget chain that executes arbitrary code. No authentication or special privileges. Just a crafted request to an endpoint that deserializes untrusted data. Insecure deserialization is mapped to CWE-502 and is included under A08:2025 Software or Data Integrity Failures in the OWASP Top 10.
What Is Insecure Deserialization?
Serialization converts an object (data structures, application state) into a format you can store or transmit. Deserialization reconstructs that object from the serialized format. The problem arises when an application rebuilds objects from untrusted data without validating which types, methods, or side effects will trigger during reconstruction.
Serialization and Deserialization
Here’s the normal flow: Application serializes an object, stores or transmits it, then deserializes it back into memory. Safe because you control the data.
Here’s the attack: An attacker intercepts and modifies the serialized data. When the application deserializes it, it doesn't reconstruct a legitimate object; instead, it instantiates a chain of classes and methods (gadgets) whose side effects execute the attacker’s code. By the time deserialization finishes, the attacker has achieved remote code execution or unauthorized access.
Applications serialize objects constantly: storing session state in cookies, caching data in Redis, transmitting objects between services, sending data through message queues. The assumption is that the serialized data is trusted. When it isn't, an attacker can manipulate the serialized payload to craft an object that runs code as a side effect of deserialization.
Languages handle this differently. Java serialization uses ObjectInputStream.readObject(). PHP uses unserialize(). Python uses pickle. Ruby uses Marshal. All encode data, type information, and method invocations, making them vulnerable when deserialization touches untrusted input.
The Trust-Boundary Failure
Deserialization is inherently dangerous because reconstructing an object triggers code: constructors fire, magic methods execute, class callbacks run. If the attacker controls the serialized input, they control what gets instantiated.
According to MITRE's CWE-502 (Deserialization of Untrusted Data), the vulnerability arises when an application deserializes untrusted data without validation. The attacker crafts a malicious payload that chains existing code fragments into an unintended action, typically remote code execution.
How Insecure Deserialization Attacks Work
The attack follows a predictable path: the attacker supplies a malicious serialized object where the application expects a trusted one. During deserialization, the reconstruction process instantiates classes and invokes methods specified in the payload. If those classes and methods exist in the application or its dependencies, the attacker can chain them together into a gadget chain that performs a dangerous action.
Manipulated Object Input
An attacker intercepts or crafts a serialized payload by modifying object properties, changing object types, or injecting method calls that don't exist in legitimate payloads. The attacker might alter a session cookie containing a serialized user object, inject a malicious serialized cache entry, or craft a request body that the application deserializes expecting a trusted type.
Tools like ysoserial for Java automatically generate known gadget chains. The attacker simply sends the output as the serialized payload. For languages like PHP, the attacker manually constructs an unserialize() string that triggers the target gadget chain.
Gadgets and Side Effects
A gadget is a code sequence that runs during deserialization. A gadget chain combines multiple gadgets whose side effects produce an attacker's goal. The danger is that gadget chains exist in your dependencies, not your code. A logging library, data-processing framework, or serialization helper might contain dormant chains. Your code might never call them, but a malicious serialized object instantiates them during deserialization.
Real-World Example: CVE-2019-2725
Oracle WebLogic Server contained a critical deserialization vulnerability in the wls9_async_response.war and wls-wsat.war components. These components deserialize SOAP requests containing XML data without validating object types. An attacker could send a specially crafted SOAP request with malicious XML to the AsyncResponseService endpoint and trigger remote code execution on any vulnerable WebLogic instance.
Oracle WebLogic Server’s vulnerability worked like this: the AsyncResponseService endpoint accepted SOAP requests containing XML data. WebLogic deserialized that XML without validating object types. Because WebLogic’s classpath contained known gadget chains from its own libraries, an attacker could craft a malicious SOAP request that, when deserialized, chained those classes together to execute arbitrary commands on the server. No credentials required. The attacker only needed to send a specially crafted request to a publicly accessible endpoint.
When proof-of-concept code was disclosed in April 2019, the vulnerability spread rapidly because the attack chain was so straightforward. This shows why insecure deserialization matters: the endpoint, the framework, and the gadget chains all existed in production code. Only the attacker’s ability to recognize and chain them together was new.
Risks and Warning Signs of Insecure Deserialization
Potential Security Impact
Insecure deserialization can lead to remote code execution when the application's runtime includes available gadget chains. The attacker's code runs with the application process's privileges. In a web application, that might be the web server's privileges. In an enterprise Java service, that might be database credentials or API keys the application holds. The attacker can then pivot to internal systems, exfiltrate data, or establish persistence.
Beyond remote code execution, insecure deserialization can lead to privilege escalation if the gadget chain invokes administrative functions, authentication bypass if it manipulates session state, data tampering if it modifies objects before they're used, denial of service if it exhausts resources, and information disclosure if the gadget chain reads files or environment variables.
Common Warning Signs
Serialized data crossing trust boundaries is the red flag: cookies, session tokens, API request bodies, cache entries, file uploads, or plugins deserialized without validation. Dangerous serialization formats also indicate risk: ObjectInputStream in Java, unserialize() in PHP, pickle in Python, Marshal in Ruby, or BinaryFormatter in .NET.
How to Detect Insecure Deserialization
Detecting insecure deserialization requires both architecture review and controlled testing because the vulnerability depends on which gadget chains are actually reachable in your specific runtime.
Code and Dependency Review
Inventory all deserialization calls: ObjectInputStream in Java, unserialize() in PHP, pickle in Python, Marshal in Ruby. Identify trust boundaries: is the serialized data user-controlled or attacker-modifiable? Map your dependencies and check for known vulnerable gadget chains using tools like ysoserial for Java.
Targeted Security Testing
This is where ethical hacking becomes essential. A penetration tester can craft payloads, inject them at deserialization endpoints, and observe whether the gadget chain executes or fails.
The OWASP Web Security Testing Guide covers testing methodology for insecure deserialization: identify trust boundaries, monitor for gadget chains, craft targeted payloads, and verify execution.
The tester verifies whether gadget chains instantiate, whether methods invoke as expected, and whether attacks produce observable side effects: code execution, file creation, network connections, or timing delays.
How to Prevent Insecure Deserialization
Prevention relies on eliminating unsafe deserialization, then adding strict controls and monitoring as a defense-in-depth measure.
Safer Data Formats
Stop using language-native object serialization for data crossing trust boundaries. Replace Java serialization with JSON, PHP unserialize() with json_decode(), Python pickle with JSON. These formats encode only data values, not object types or methods, so attackers can't exploit a gadget chain.
If you must use native serialization, limit it to internal communication where the source is protected. A cookie or API request body must never contain serialized objects.
Strict Type Controls
Use allowlists to specify exactly which classes can be deserialized. Set depth and size limits to prevent resource exhaustion. Validate field types and values against a schema. Reject any serialized object with unexpected metadata or types. Monitor deserialization failures for signs of attack.
Defense in Depth
Patch your dependencies regularly because gadget chains often come from libraries. Run static analysis tools to identify deserialization calls in your code and review them for trust-boundary issues. Minimize the application process's runtime privileges so that, even if an attacker exploits deserialization, their code runs with limited permissions. Restrict outbound network access so the attacker cannot exfiltrate data or command the application to attack other systems. Monitor deserialization failures and unexpected exceptions that might indicate an attack in progress.
For regulated industries such as healthcare and fintech, secure coding training for development teams reduces the likelihood of introducing deserialization vulnerabilities. For healthcare environments, healthcare penetration testing validates that your controls account for patient data sensitivity and compliance obligations.
Remember that signatures and whitelisting are supplementary controls only. They make known gadget chains harder to exploit, but they don't reliably defend against deserialization vulnerabilities because new gadget chains are discovered regularly.
Insecure Deserialization FAQs
Is all deserialization insecure?
Deserialization of untrusted data without validation is insecure. Deserializing trusted or validated data can be safe. Risk arises when you deserialize data an attacker can modify, and that data touches code with usable gadget chains.
Can JSON deserialization be unsafe?
JSON is safer than native formats because most libraries deserialize to plain data structures. However, frameworks that allow polymorphic types or automatically construct classes from type hints can reintroduce gadget-chain risk. Check your framework documentation.
What is a gadget chain?
A sequence of methods and callbacks already in your code or dependencies that, when combined during deserialization, produce a dangerous outcome. The attacker doesn't write gadgets; they chain existing ones together by crafting a malicious serialized payload.
Why do we need manual penetration testing if we have static analysis tools?
Static analysis can identify dangerous deserialization functions and dependencies. The harder question is whether an attacker can reach and exploit a gadget chain at runtime.
Manual pentesting validates that attack path by testing serialized inputs, identifying reachable gadgets, and safely demonstrating impact.



