Articles

What Is Insecure Deserialization?

Insecure deserialization lets attackers turn a trusted object format into remote code execution. How the attack works and how to prevent it.

Chisato Chisato · · 4 min read
Red padlock icon over a keyboard

Insecure deserialization is a vulnerability where an application reconstructs objects from untrusted, attacker-controlled data without verifying that the data is safe — and in the worst cases, that reconstruction process itself lets an attacker execute arbitrary code, long before the resulting object is ever used. It’s one of the more severe entries in the OWASP Top 10, because a successful exploit frequently leads straight to remote code execution rather than a more limited information leak.

Serialization and deserialization, briefly

Serialization converts an in-memory object into a format that can be stored or transmitted — a byte stream, a string, a file. Deserialization reverses that process, reconstructing the original object from the serialized form. This is routine and necessary: sessions, caches, message queues, and inter-service communication all rely on serializing data at one end and deserializing it at the other.

The danger appears when the serialized data being deserialized comes from somewhere untrusted — a cookie, a form field, an uploaded file, a message from another service you don’t fully control — and the deserialization process does more than just populate plain data fields.

Why deserialization can lead to code execution

Many serialization formats used by mainstream languages (Java’s native serialization, PHP’s unserialize, Python’s pickle, and similar mechanisms in other ecosystems) don’t just restore data — they can also restore object type and trigger lifecycle methods during reconstruction, such as constructors, destructors, or “wakeup” hooks that run automatically when an object of a given class is created.

An attacker who can control the serialized payload can specify that it deserializes into a class already present in the application (or one of its dependencies) whose lifecycle methods have a dangerous side effect — writing a file, opening a connection, invoking a shell command. Chaining several such classes together, where one method’s side effect sets up the conditions for the next, is known as building a “gadget chain.” The attacker never needs to inject new code; they only need to invoke code that’s already loaded, in a sequence the developers never intended.

This is fundamentally different from something like SQL injection, where the danger is malicious data changing a query’s meaning. Here, the danger is malicious data changing which code executes during a supposedly inert data-loading step.

What it looks like in practice

A typical vulnerable pattern: an application stores some state — user preferences, a shopping cart, a session token — as a serialized object in a cookie or hidden form field, trusting the client to send it back unmodified. If the format isn’t cryptographically signed, an attacker can craft their own serialized payload, drop it into that field, and submit it. The server deserializes it as if it were the original trusted object, and the crafted gadget chain fires during that process.

The same risk shows up in server-to-server contexts: a message queue or internal API that deserializes payloads from another service without validating the sender’s trust boundary is just as exposed if that boundary is ever crossed — by a compromised dependency, a misconfigured network, or a malicious insider.

How to prevent it

Avoid deserializing untrusted data with formats that support object reconstruction and lifecycle hooks. This is the most reliable fix. Where you have a choice, prefer data-only formats — see JSON vs YAML for a comparison of formats commonly substituted in for native object serialization, since a plain data format with no execution semantics can’t trigger a gadget chain no matter what values it contains.

If you must deserialize potentially untrusted data:

  • Verify integrity before deserializing. Sign the serialized payload with HMAC or a similar mechanism, and reject anything whose signature doesn’t match, before the deserializer ever touches the bytes.
  • Use allow-lists for types. Many serialization libraries support restricting deserialization to a known-safe set of classes, refusing to instantiate anything outside that list.
  • Isolate the deserialization step. Run it in a low-privilege process or sandbox, following the principle of least privilege, so that even a successful gadget chain has little to act on.
  • Keep dependencies patched. Gadget chains are usually built from classes in third-party libraries. Removing or updating a vulnerable library removes a link in the chain even if the application code never changes.

Apply input validation and sanitization consistently at the boundary, per the general principles in input validation vs sanitization vs escaping — deserialization deserves the same “never trust the client” posture as any other user-controlled input, even when the format looks structured and internal.

Insecure deserializationSQL injectionBuffer overflow
Root causeUntrusted data reconstructed into live objects with side effectsUntrusted data alters query structureUntrusted data overflows a fixed-size buffer
Typical impactRemote code executionData theft or manipulationMemory corruption, potential RCE
Primary fixAvoid deserializing untrusted data; sign/validate payloadsParameterized queriesBounds checking, memory-safe languages

See what a buffer overflow is for the memory-safety analog to this class of bug, and what a zero-day vulnerability is for how newly discovered gadget chains in popular libraries tend to get disclosed and patched.

The takeaway

Insecure deserialization turns a routine data-loading step into a code execution path by exploiting formats that reconstruct object type and trigger lifecycle methods automatically. The safest fix is to never deserialize untrusted data with a format capable of that behavior in the first place; where that’s unavoidable, sign the payload, restrict the types that can be instantiated, and keep the libraries providing the gadget chain’s building blocks patched.

Chisato Chisato · · 4 min read

Trusted Types API: Stopping DOM XSS at the Sink

The Trusted Types API blocks DOM-based XSS by forcing risky DOM sinks like innerHTML to accept only vetted objects instead of raw strings.

#Security #Web Development #JavaScript
Chisato Chisato · · 6 min read

LiteLLM CVE-2026-59822: CISA KEV AI Infra Attacks

CISA added seven exploited flaws to its KEV catalog on Sept. 2, and three target AI infrastructure — LiteLLM, Kestra, and Starlette. What to patch and why it matters.

#Security #Vulnerability #AI