Safeguard
Industry Analysis

Insecure deserialization attack

A precise breakdown of what is an insecure deserialization attack, how object injection and gadget chains work in Java and Python, and how to defend against them.

Aman Khan
AppSec Engineer
7 min read

Insecure deserialization is a vulnerability class that arises when an application reconstructs objects from untrusted, attacker-controlled data without verifying that the resulting object is safe. So what is an insecure deserialization attack, exactly? It is an exploit technique in which an attacker crafts a malicious serialized payload — a byte stream, JSON blob, or language-specific object graph — and feeds it to a program that deserializes it without validation, causing the application to execute arbitrary code, escalate privileges, or corrupt application logic. The flaw sits at the boundary where raw data is turned back into live objects: if that boundary trusts its input, the attacker effectively gets to define part of the program's runtime state. Deserialization bugs have powered some of the most damaging breaches of the last decade, from enterprise Java middleware compromises to Python pickle-based remote code execution, and OWASP has ranked deserialization risks among its top ten application security categories for years.

What Is an Insecure Deserialization Attack at the Code Level?

At the code level, an insecure deserialization attack happens when a program calls a deserialization function on data it did not generate itself and cannot fully trust — think ObjectInputStream.readObject() in Java, pickle.loads() in Python, or unserialize() in PHP — without restricting which classes can be instantiated or what those classes do during construction. Serialization formats don't just encode data; they encode type information and, in many languages, they can trigger code execution as a side effect of rebuilding an object. Java, for instance, invokes special methods like readObject(), readResolve(), or finalize() automatically during deserialization. If any class reachable on the application's classpath performs a dangerous operation inside one of those methods — writing a file, opening a socket, invoking a shell — an attacker who controls the serialized bytes can chain several such classes together into a "gadget chain" that ends in arbitrary command execution, all without ever calling a method directly.

Why Is This Often Called an Object Injection Attack?

This is often called an object injection attack because the attacker is not injecting a string of code but injecting a fully formed object — or a chain of objects — into the application's memory space, and the application's own logic does the damage when it processes them. In PHP and Java ecosystems especially, "object injection" and "insecure deserialization" are used almost interchangeably: the attacker submits a serialized representation of an object whose class exists somewhere in the target's loaded libraries, and when the framework deserializes it, the object's constructor, destructor, or magic methods fire with attacker-chosen property values. A classic PHP example is crafting a serialized object of a class that has a __destruct() method performing a file deletion or SQL query built from object properties; the attacker sets those properties to whatever values drive the query or file path they want. No traditional injection point like a form field carrying a script tag is needed — the object itself is the payload.

What Is a Java Deserialization Vulnerability and Why Is It So Common?

A Java deserialization vulnerability is a flaw that lets an attacker abuse Java's native object serialization mechanism to achieve remote code execution, and it remains common because so many enterprise Java applications ship with large dependency trees containing exploitable gadget classes. The Apache Commons Collections library became infamous in this context: security researchers demonstrated that certain classes within it, such as InvokerTransformer, could be chained together during deserialization to invoke arbitrary methods via Java reflection, ultimately calling Runtime.exec(). Because Commons Collections was bundled inside countless enterprise products, the same gadget chain compromised WebLogic, WebSphere, JBoss, Jenkins, and other widely deployed platforms in 2015 and the years following, all through the same root cause: an application deserializing untrusted Java objects without restricting which classes could be instantiated. Patching the vulnerable application often wasn't enough, since the dangerous gadget classes lived in a shared library many layers removed from the code the development team actually wrote.

How Does a Pickle Deserialization Exploit Work in Python?

A pickle deserialization exploit works by abusing the fact that Python's pickle module can serialize not just data but also instructions for rebuilding arbitrary objects, including a call to __reduce__() that pickle will execute automatically on load. An attacker can define a class whose __reduce__() method returns a tuple pointing at os.system or subprocess.Popen along with a shell command, pickle that object, and hand the resulting bytes to any application that calls pickle.loads() on them. The moment the victim application unpickles the data, the attacker's command runs with the privileges of that process — no separate exploit stage required. This pattern has repeatedly surfaced in machine learning pipelines, where pretrained model files are distributed as pickle archives and loaded by data scientists who assume a model file is inert data rather than executable logic, and in caching layers like Redis or Memcached-backed sessions where cached objects are pickled and later restored without integrity checks.

What Do the OWASP Deserialization Risks Guidelines Actually Recommend?

The OWASP deserialization risks guidance recommends, first and foremost, avoiding deserialization of untrusted data altogether whenever a safer alternative exists, such as exchanging plain JSON or XML with strict schema validation instead of native object serialization formats. Where deserialization of external data is unavoidable, OWASP's Deserialization Cheat Sheet advises implementing integrity checks like digital signatures on serialized objects, running deserialization logic in a low-privilege, sandboxed process, enforcing strict type constraints (such as Java's ObjectInputFilter or look-ahead deserialization allow-lists), and logging deserialization exceptions so repeated attack attempts are visible to defenders. OWASP also recommends monitoring network traffic for outbound connections initiated immediately after inbound deserialization calls, since gadget chain execution frequently triggers callback or exfiltration attempts that stand out from normal application behavior. These controls exist because deserialization vulnerabilities are structurally different from typical injection flaws: the vulnerable code is often deep inside a third-party library, invisible in the application's own source, which is why OWASP frames this as a supply chain-adjacent risk category rather than a simple coding mistake.

Where Have Insecure Deserialization Attacks Caused Real Damage?

Insecure deserialization attacks have caused real, well-documented damage across both commercial and open-source ecosystems, with the Apache Commons Collections gadget chains standing as the canonical example: once published, the same technique was used to compromise Oracle WebLogic Server, IBM WebSphere, Jenkins CI servers, and Cisco security products, because each embedded a vulnerable version of the library and deserialized attacker-reachable Java objects somewhere in its request-handling path. Equally instructive is the recurring pattern in Python tooling, where security teams have found malicious pickle files uploaded to public model-sharing platforms specifically crafted to execute code the moment an unsuspecting researcher loads them. In both ecosystems, the underlying lesson is the same: deserialization vulnerabilities travel with dependencies, meaning an organization can be exposed not because of code it wrote but because of a library it imported three or four levels deep, making this fundamentally a software supply chain security problem as much as an application security one.

How Safeguard Helps

Safeguard treats insecure deserialization the way the OWASP guidance implies it should be treated: as a supply chain risk, not just a code review finding. Safeguard's software composition analysis continuously maps every dependency in an application — including the transitive libraries most teams never audit directly — and flags known-vulnerable gadget chain components such as outdated Commons Collections, Jackson, or Fastjson versions before they ship to production. For custom code, Safeguard's static analysis identifies dangerous deserialization sinks like readObject(), pickle.loads(), or unserialize() calls that accept untrusted input without allow-listing, signature verification, or sandboxing, giving engineering teams the exact file and line where an object injection attack could enter the system. Because deserialization flaws are frequently introduced or reintroduced through routine dependency upgrades, Safeguard's continuous monitoring re-evaluates the software bill of materials on every build, alerting security teams the moment a newly disclosed Java deserialization vulnerability or pickle-based CVE affects a package already running in their environment — turning what is historically a blind spot into a tracked, remediated risk.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.