OWASP Top 10: Insecure Deserialization
What Is Deserialization?
Continue your mission
What Is Deserialization?
# OWASP Top 10: Insecure Deserialization
Insecure deserialization is a vulnerability class that occurs when an application reconstructs objects from serialized data without validating the integrity, type, or content of that data. Catalogued as A08 in the OWASP Top 10 (2021), it represents one of the most dangerous yet underestimated risks in modern software development.
Serialization converts complex in-memory objects into portable formats for transmission across networks, storage in databases, or passage between application components. Deserialization reverses this process. The vulnerability exists because most deserialization routines prioritized convenience and interoperability over security. They were designed for cooperative environments, not adversarial ones.
The risk extends beyond accepting malformed data. Insecure deserialization fundamentally breaks the trust relationship between a deserializer and its input. When applications treat serialized input with the same trust level as internal data, attackers gain the ability to manipulate object graphs, trigger unexpected method invocations, and achieve arbitrary code execution without authentication.
This vulnerability spans all serialization formats. Binary formats like Java's native serialization, Python's pickle, and .NET's BinaryFormatter carry type metadata that instructs runtimes which classes to instantiate, making them particularly dangerous. Text-based formats like JSON and XML are generally safer because most parsers don't automatically instantiate arbitrary objects. However, polymorphic deserialization features in libraries like Jackson or XStream can reintroduce this risk when type handling is enabled carelessly.
Insecure deserialization differs from injection vulnerabilities. SQL injection inserts malicious strings into database queries. Command injection inserts malicious strings into system calls. Insecure deserialization operates at the object layer: attackers construct serialized object graphs that cause runtimes to call methods on classes already present in the application's classpath.
When a runtime deserializes an object, it performs more than memory allocation. The process reads type metadata from the serialized stream, locates corresponding class definitions, allocates instances, and populates their fields. Critically, this process automatically invokes lifecycle methods: constructors, readObject handlers, magic methods, or finalizers. These methods execute application code. If attackers control what class gets instantiated and what field values it holds, they control what code runs.
Attackers don't need to introduce new code. They work entirely with classes already loaded in the runtime through a technique called gadget chaining. A gadget is a class whose existing method, when invoked during deserialization with attacker-controlled field values, performs a step toward code execution. A gadget chain strings multiple gadgets together so the final link executes operating system commands, writes web shells, or establishes reverse connections.
Java's ObjectInputStream.readObject() serves as the entry point for Java's native binary serialization. When applications receive serialized objects, readObject() traverses the object graph and invokes each class's readObject() method if defined. The Apache Commons Collections library (versions prior to 3.2.2 and 4.1) contained classes whose method invocations could be chained to call Runtime.exec(), Java's system command execution method.
An attacker targeting vulnerable Java applications would:
This mechanism was present in the Apache Struts vulnerability (CVE-2017-9805) and central to WebLogic server compromises affecting Oracle Fusion Middleware deployments.
Python's pickle module deserializes objects by executing opcode sequences. The __reduce__ method controls how classes are pickled and unpickled. Attackers controlling pickled payloads can define __reduce__ to return a callable and arguments, causing the callable to execute during unpickling. The canonical payload calls os.system() or subprocess.Popen() with attacker-specified commands. Any Python application unpickling data from network sources, cache layers like Redis or Memcached, or message brokers without integrity verification faces potential compromise.
PHP's unserialize() function reconstructs PHP objects from serialized strings. PHP automatically calls the magic method __wakeup() when objects are deserialized and __destruct() when objects are garbage collected. Attackers craft serialized strings that instantiate classes with dangerous __destruct() or __wakeup() implementations. Classes that delete files, write to filesystems, or make network connections can be weaponized if constructors or lifecycle methods use attacker-controlled properties.
Consider a CMS storing user preferences as serialized strings in cookies. If applications call unserialize() on cookie values without validation, attackers can craft cookies containing serialized objects of classes that perform file inclusion or write PHP code to disk.
Microsoft's BinaryFormatter, used in .NET applications for remoting and session state, deserializes type information embedded in binary streams. Gadget chains analogous to Java's exist for .NET. Microsoft has deprecated BinaryFormatter and disabled it by default in .NET 7 and later, but applications on older frameworks remain exposed.
Insecure deserialization vulnerabilities frequently appear where developers don't initially recognize attack surfaces: session state in cookies, message queue payloads, caching layer entries, inter-service communication in microarchitectures, and RMI endpoints. Any boundary where serialized data crosses from untrusted domains into deserializers represents potential attack surface.
Insecure deserialization impact scales with post-exploitation capabilities. At minimum, attackers may tamper with object properties to bypass authentication checks, elevate privileges, or access other users' data. At maximum, attackers achieve unauthenticated remote code execution, gaining full application process control, database access, and footholds for lateral network movement.
Remote code execution via deserialization is particularly damaging because it bypasses perimeter controls. Malicious payloads arrive over the same ports and protocols as legitimate traffic. Web application firewalls inspecting for SQL injection patterns or cross-site scripting strings may not detect binary serialized gadget chains. Attacks require no credentials and frequently leave minimal log evidence unless applications explicitly log raw input at deserialization boundaries.
The 2017 Equifax breach exposed personal financial information of approximately 147 million Americans. Initial access came through an Apache Struts vulnerability (CVE-2017-5638) involving unsafe deserialization of HTTP headers processed by the Jakarta Multipart parser. Equifax had failed to apply patches available for months. The breach resulted in regulatory settlements exceeding $575 million, congressional testimony, and lasting reputational damage. This incident proved deserialization vulnerabilities aren't theoretical—they're exploited at scale with consequences extending far beyond technical teams.
Organizations often underestimate deserialization risk because the vulnerability appears in unexpected places. A shopping cart stored in session cookies, a message queue payload in a microservices architecture, or a cached object in Redis can all become attack vectors. The attack surface grows with application complexity, particularly in distributed systems where serialized objects cross service boundaries frequently.
A persistent misconception holds that only Java applications face deserialization vulnerabilities. As demonstrated, Python, PHP, .NET, Ruby, and other languages all have exploitable serialization mechanisms. Another misconception suggests that moving to text-based formats like JSON automatically eliminates risk. Libraries supporting polymorphic type handling, such as Jackson with default typing enabled, can be configured to allow type-based gadget chains through JSON payloads. Format matters less than deserializer behavior and input trust levels.
CDA frames insecure deserialization within the Secure Posture Hygiene (SPH) domain of the Planetary Defense Model. SPH focuses on continuous, automated maintenance of security postures that don't degrade between scheduled assessments. The governing methodology is Autonomous Posture Command (APC), expressed as: "Your posture adapts. Your hygiene never sleeps."
Deserialization vulnerabilities exemplify risks that point-in-time assessments miss. A Java application may be safe today because vulnerable library versions are absent from the classpath. Tomorrow, a dependency update introduces libraries containing gadget chains. Without continuous inventory of serialization-capable libraries and automated detection of deserializer inputs, exposure windows remain invisible.
CDA's APC methodology addresses insecure deserialization through four operational actions:
Continuous deserialization surface mapping maintains living inventories of every application component accepting serialized input, including HTTP endpoints, message brokers, caching layers, and inter-service channels. These inventories aren't quarterly-updated spreadsheets but machine-readable asset graphs updated on every deployment event.
Gadget chain library tracking correlates applications' software bills of materials (SBOMs) against known gadget chain libraries sourced from ysoserial's payload list, MITRE ATT&CK's T1059 subtechniques, and vendor security advisories. When vulnerable library versions enter dependency trees, alerts trigger before deployment completion.
Deserialization input enforcement pushes configuration baselines enforcing serialization allow-lists (Java's ObjectInputFilter, .NET's SerializationBinder, Python's restricted unpickling patterns) and signs serialized payloads with HMAC before transmission, verifying signatures before deserialization. These controls are enforced as policy, not guidelines.
Behavioral anomaly detection at deserialization boundaries instruments application runtimes to detect unexpected class instantiation during deserialization, specifically classes not included in pre-approved lists. Runtime telemetry feeds posture dashboards, providing near-real-time visibility into exploitation attempts that may not produce traditional log entries.
CDA Theater missions that address topics covered in this article.
Cryptographic technique that encrypts data while preserving its original format and length, enabling protection without breaking legacy system compatibility.
Guide to HTTP/2 security covering binary framing, HPACK compression attacks, rapid reset vulnerability, stream multiplexing risks, and mitigation strategies.
Explanation of Certificate Transparency framework, covering log servers, Signed Certificate Timestamps, monitoring capabilities, and detection of fraudulent certificates.
Written by CDA Wiki Team
Found an issue? Help improve this article.