Skip to main content
Category: Vulnerability Management

Insecure Deserialization

Also known as: Untrusted Deserialization
Simply put

Insecure deserialization is a security flaw that occurs when an application converts data from a stored or transmitted format back into an object without properly checking whether that data has been tampered with. An attacker can exploit this by crafting malicious data that, when processed by the application, can lead to unauthorized actions such as executing harmful code or manipulating application logic. It was notably listed in the OWASP Top 10 as a significant web application risk.

Formal definition

Insecure deserialization is a vulnerability class that arises when user-controllable or otherwise untrusted data is passed to an application's deserialization routines without adequate validation, integrity checks, or type constraints. By manipulating serialized objects, an attacker can abuse the application's deserialization logic to achieve outcomes including, but not limited to, remote code execution, injection attacks, privilege escalation, and replay attacks. The severity depends on the deserialization library in use, the available gadget chains within the application's classpath or runtime environment, and whether the application enforces allowlists on deserializable types. This vulnerability typically affects languages and frameworks that support native object serialization (such as Java, PHP, Python, and .NET) and may be difficult to detect through static analysis alone, since exploitability often depends on the presence of specific classes and libraries available at runtime.

Why it matters

Insecure deserialization is significant because, in the worst case, it can enable remote code execution (RCE), giving an attacker the ability to run arbitrary commands on the server with the same privileges as the application. Even when RCE is not achievable, exploitation may still lead to privilege escalation, injection attacks, replay attacks, or manipulation of application logic. The severity of a given instance depends on the deserialization library in use, the gadget chains available in the application's classpath or runtime environment, and whether any allowlists constrain the types that can be deserialized. This combination of high impact and context-dependent exploitability makes it a particularly dangerous and often underestimated vulnerability class.

The risk was recognized prominently when insecure deserialization was included in the OWASP Top 10 as a significant web application security risk. It typically affects languages and frameworks that support native object serialization, such as Java, PHP, Python, and .NET. Because exploitability often hinges on runtime conditions (the presence of specific classes and libraries), the vulnerability may be difficult to detect through static analysis alone. This means organizations relying solely on code-level scanning may have a blind spot for deserialization risks, making defense-in-depth strategies and runtime protections especially important.

Who it's relevant to

Application Developers
Developers working with languages and frameworks that support native object serialization (Java, PHP, Python, .NET, and others) need to understand the risks of passing untrusted data to deserialization routines. Choosing safer data formats, applying type-constrained deserialization, and enforcing allowlists on deserializable classes are critical defensive practices.
Application Security Engineers
Security engineers must recognize that insecure deserialization is often difficult to detect through static analysis alone because exploitability depends on the gadget chains available at runtime. Effective assessment typically requires a combination of code review, dependency analysis to identify known gadget chain libraries, and dynamic or runtime testing.
Software Architects
Architects should design systems to minimize or eliminate the use of native object serialization for untrusted inputs. Selecting data interchange formats that do not support arbitrary object instantiation and enforcing integrity checks on serialized data at trust boundaries are important architectural decisions.
Penetration Testers and Red Teams
Testers targeting deserialization vulnerabilities need to understand the specific serialization formats, libraries, and available gadget chains in the target environment. Exploitation is highly context-dependent, requiring knowledge of the application's runtime classpath and the deserialization mechanisms in use.
Security Operations and Incident Response Teams
Deserialization attacks can result in remote code execution and other high-severity outcomes, making rapid detection and response essential. Monitoring for anomalous deserialization activity and maintaining awareness of known deserialization vulnerabilities in deployed libraries and frameworks helps reduce response time.

Inside Insecure Deserialization

Serialization
The process of converting an in-memory object or data structure into a format suitable for storage or transmission, such as a byte stream, JSON, XML, or a language-specific binary format.
Deserialization
The reverse process of reconstructing an object or data structure from its serialized representation back into memory, which may invoke constructors, setters, or callback methods depending on the language and framework.
Untrusted Input
Serialized data originating from sources outside the application's trust boundary, such as user-supplied cookies, API parameters, message queues, or inter-service payloads, that has not been validated or integrity-checked before deserialization.
Gadget Chain
A sequence of existing classes or methods within an application's classpath or runtime environment that, when chained together during deserialization, can be exploited to achieve unintended effects such as remote code execution, file access, or denial of service.
Object Injection
An attack pattern in which a crafted serialized payload causes the deserializer to instantiate arbitrary or unexpected objects, potentially triggering dangerous side effects through magic methods, finalizers, or overridden callbacks.
Type Confusion
A condition arising when the deserialization process reconstructs an object of a different type than expected by the application, which may bypass security checks or lead to logic errors and further exploitation.
Remote Code Execution (RCE)
The most severe potential consequence of insecure deserialization, where an attacker achieves arbitrary command or code execution on the server by exploiting gadget chains or language-level object reconstruction behaviors.

Common questions

Answers to the questions practitioners most commonly ask about Insecure Deserialization.

Is insecure deserialization only a problem in Java applications?
No. While Java deserialization vulnerabilities have received significant attention due to high-profile exploits involving libraries like Apache Commons Collections, insecure deserialization affects many languages and frameworks. Python (via pickle), PHP (via unserialize), Ruby (via Marshal), .NET (via BinaryFormatter and others), and JavaScript (via certain libraries) are all susceptible. The specific exploitation techniques and gadget chains differ across languages, but the fundamental vulnerability, trusting serialized data from untrusted sources, is language-agnostic.
Does using JSON instead of binary serialization formats eliminate deserialization risks?
Not entirely. While JSON deserialization is generally less prone to the classic object injection and remote code execution attacks associated with native binary serialization formats, it is not inherently safe. If a JSON deserializer is configured to instantiate arbitrary types based on type hints embedded in the data (as can occur with libraries like Jackson in Java when polymorphic type handling is enabled, or Newtonsoft.Json in .NET with TypeNameHandling), attackers may still achieve code execution or other unintended behavior. JSON-based deserialization can also lead to denial of service through deeply nested structures or excessively large payloads.
How can static analysis tools help detect insecure deserialization, and what are their limitations?
Static analysis (SAST) tools can typically identify calls to known dangerous deserialization functions (such as ObjectInputStream.readObject in Java, pickle.loads in Python, or unserialize in PHP) and flag cases where untrusted input flows into those calls. However, SAST tools generally cannot determine whether a sufficient allowlist or custom deserialization logic is in place at runtime, and they may produce false positives when safe wrappers or mitigations exist. They also typically cannot discover exploitable gadget chains, since that depends on the full set of classes available on the runtime classpath, which is a deployment-context concern rather than a purely static one.
What are the most effective mitigations for preventing insecure deserialization in production systems?
The most effective mitigations include: avoiding native deserialization of untrusted data entirely where possible; using data-only serialization formats (such as JSON or Protocol Buffers) without polymorphic type resolution; implementing strict allowlists of permitted classes if native deserialization is required; applying integrity checks (such as HMACs or digital signatures) to serialized data before deserialization; and isolating deserialization processes with reduced privileges. Defense in depth is important because no single control addresses all attack vectors. Keeping libraries and frameworks patched to remove known gadget classes is also a practical necessity.
How should deserialization endpoints be tested during security assessments?
Testing typically involves identifying endpoints or data flows that accept serialized objects, then attempting to supply crafted payloads. For binary formats, tools such as ysoserial (Java), ysoserial.net (.NET), or custom scripts for Python pickle can generate known gadget chain payloads. Testers should also check for error messages that reveal deserialization behavior, test whether type restrictions or allowlists are enforced, and verify whether integrity checks on serialized data can be bypassed. Dynamic testing (DAST) tools may detect some cases through error-based heuristics, but they generally have limited coverage for deserialization flaws because exploitation often requires language-specific and application-specific gadget chains. Manual and semi-automated testing tends to be more effective for thorough coverage.
How can organizations monitor for deserialization attacks at runtime?
Runtime monitoring approaches include deploying Runtime Application Self-Protection (RASP) agents that can intercept deserialization calls and enforce class allowlists or block known malicious patterns, as well as using web application firewalls (WAFs) configured with signatures for common serialized object patterns (though WAF detection of binary serialized payloads may have high false negative rates for obfuscated or novel payloads). Application-level logging of deserialization events, including recording the types being instantiated and flagging unexpected classes, provides valuable detection data. Java applications can also leverage JEP 290 deserialization filters to restrict which classes are permitted during deserialization, and violations can be logged for security monitoring.

Common misconceptions

Insecure deserialization only affects Java applications.
While Java's native serialization mechanism is among the most widely publicized attack surfaces, insecure deserialization vulnerabilities occur across many languages and frameworks, including Python (pickle), PHP (unserialize), Ruby (Marshal), and .NET (BinaryFormatter). Any language that supports reconstructing objects from serialized data can be affected.
Using JSON instead of binary serialization formats eliminates deserialization risks.
JSON-based deserialization can still be vulnerable when the deserializer supports polymorphic type handling or type hints (for example, Jackson with default typing enabled, or Newtonsoft.Json with TypeNameHandling). The risk depends on whether the deserializer instantiates objects based on attacker-controlled type information, not solely on the data format.
Static analysis tools can reliably detect all insecure deserialization vulnerabilities.
Static analysis (SAST) can typically identify calls to known dangerous deserialization functions and flag the use of risky configurations. However, it generally cannot determine whether a reachable gadget chain exists at runtime, assess the full exploitability of a deserialization sink, or evaluate whether network-level controls adequately mitigate the risk. Confirming exploitability in most cases requires dynamic analysis, manual review, or specialized tooling that maps available gadget chains.

Best practices

Avoid deserializing data from untrusted or unauthenticated sources whenever possible; prefer simpler data exchange formats such as plain JSON without polymorphic type resolution.
Implement strict allowlists (whitelists) of permitted classes or types that the deserializer is allowed to instantiate, rather than relying on denylists, which are typically incomplete against novel gadget chains.
Apply integrity checks such as HMAC signatures or digital signatures to serialized payloads before deserialization, ensuring that only data produced by trusted components is accepted.
Monitor and restrict deserialization endpoints by enforcing authentication, authorization, and input size limits, and log deserialization failures as potential indicators of attack activity.
Keep libraries, frameworks, and runtime environments up to date, as known gadget chain classes are frequently patched or removed in newer versions, reducing the available attack surface.
Use language-specific hardening options where available, such as Java's ObjectInputFilter, .NET's SerializationBinder restrictions, or disabling dangerous deserializer features like Jackson's default typing, to constrain deserialization behavior at the framework level.