Weakness reference
CWE-502

Deserialization of Untrusted Data

Deserialization is the process of converting serialized data often a byte stream or string back into an object or data structure. When an application…

01Summary

Deserialization is the process of converting serialized data (often a byte stream or string) back into an object or data structure. When an application deserializes data from an untrusted source—such as user input, network traffic, or uploaded files—without proper validation, an attacker can craft malicious serialized payloads that execute arbitrary code or trigger unintended application logic. This is one of the most dangerous classes of vulnerability because it often leads directly to remote code execution.

02How It Happens

Serialization formats like Python's pickle, PHP's unserialize(), Java's ObjectInputStream, and others can encode not just data but also instructions for reconstructing complex objects. When an application blindly deserializes untrusted input, it may instantiate attacker-controlled objects with malicious constructors or magic methods (__wakeup(), __destruct(), etc.) that execute code during the deserialization process itself. The vulnerability is especially severe when the application's class library includes "gadget chains"—sequences of existing classes whose methods can be chained together to perform dangerous operations like file writes, command execution, or database manipulation.

03Real-World Impact

Successful exploitation typically results in remote code execution with the privileges of the application process. An attacker can read or modify sensitive files, steal database credentials, pivot to other systems on the network, or establish persistent backdoors. Even if code execution is not directly achieved, deserialization flaws can lead to denial of service, authentication bypass, or logic manipulation that compromises data integrity.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import pickle
import base64

# Receives serialized data from an HTTP request parameter
serialized_data = request.args.get('data')
decoded = base64.b64decode(serialized_data)

# Directly deserializes without validation
user_object = pickle.loads(decoded)

Why it's vulnerable:
pickle.loads() will execute arbitrary Python code embedded in the serialized payload. An attacker can craft a malicious pickle that runs code during deserialization.

Fixed pattern
import json

# Accept only JSON, which is data-only and cannot encode executable code
json_data = request.args.get('data')
user_object = json.loads(json_data)

# Validate the structure and types
if isinstance(user_object, dict) and 'name' in user_object:
    name = user_object['name']
    # Process safely
Vulnerable pattern
<?php
// Receives serialized data from user input
$serialized = $_POST['user_data'];

// Directly unserializes without validation
$user_object = unserialize($serialized);

// Magic methods like __wakeup() or __destruct() execute here
echo $user_object->name;
?>

Why it's vulnerable:
unserialize() will instantiate objects and invoke magic methods, allowing an attacker to trigger arbitrary code through gadget chains in loaded classes.

Fixed pattern
<?php
// Accept only JSON, which is data-only
$json_data = $_POST['user_data'];
$user_array = json_decode($json_data, true);

// Validate structure and types
if (is_array($user_array) && isset($user_array['name'])) {
    $name = sanitize_text_field($user_array['name']);
    // Process safely
}
?>

05Prevention Checklist

Avoid deserializing untrusted data entirely.
Use data-only formats like JSON or XML instead of language-specific serialization (pickle, unserialize, ObjectInputStream).
If deserialization is unavoidable, use allowlisting.
Restrict deserialization to a whitelist of known, safe classes; reject any serialized object not on the list.
Validate structure and types after deserialization.
Even with safer formats, verify that the deserialized data matches expected schemas and types before use.
Keep dependencies and frameworks patched.
Gadget chain vulnerabilities often depend on specific versions of libraries; regular updates reduce the attack surface.
Run the application with minimal privileges.
Limit the damage if deserialization is exploited by running the process as a non-root user with restricted file and network access.
Monitor for suspicious deserialization activity.
Log and alert on unexpected object instantiation or class loading, especially in security-sensitive code paths.

06Signs You May Already Be Affected

Look for unexpected processes spawning from your application, unusual outbound network connections, or files created in unexpected locations. Check application logs for errors related to object instantiation or class loading failures, which may indicate failed exploitation attempts. Review your codebase for calls to pickle.loads(), unserialize(), ObjectInputStream, or similar deserialization functions that accept user-controlled input.

07Related Recent Vulnerabilities