Insecure deserialization is when an app rebuilds objects from untrusted serialized data without validation. Because reconstruction can trigger code in many languages, an attacker who controls the input can reach remote code execution (RCE) — often from one crafted input, no credentials — via a gadget chain (existing classes strung together to a dangerous operation). It appears in Java, .NET, Python and PHP native serialization, and hides in cookies, tokens, caches, message queues and API payloads. Even without RCE it enables auth bypass and privilege escalation. The fix: don't deserialize untrusted data — prefer JSON, allow-list types, sign the data, patch libraries. Full explainer below; it's a top-priority finding in every web app test.
// 01 Serialization, and where it goes wrong
Serialization turns a live object in memory into a stream of bytes so it can be saved to disk, cached, or sent over the network; deserialization rebuilds the object from those bytes. It's everyday plumbing — until the bytes come from an attacker. Insecure deserialization is the vulnerability that arises when an application deserializes data from an untrusted source without validation. The danger is that a serialized blob doesn't just carry data — it describes objects, and in many languages reconstructing an object triggers code (constructors, magic methods, callbacks). So if an attacker controls the serialized input, they're not just supplying data; they're influencing what gets executed during reconstruction. That's the leap that makes this class of bug so severe: a data operation becomes an execution primitive.
// 02 How it becomes remote code execution
The worst outcome — and a common one — is remote code execution. Here's the shape: the attacker crafts a serialized object that, when the target deserializes it, causes methods to fire on objects in a sequence that ultimately reaches a dangerous operation like running a system command. They rarely need to write novel code — they abuse classes already present in the app and its libraries. The result is full server compromise from a single input, frequently pre-authentication, which is why insecure deserialization consistently rates critical. And even where RCE isn't reachable, the same control over reconstructed objects enables authentication bypass, privilege escalation and data tampering — for instance, deserializing a user object with an attacker-set isAdmin flag. It's rarely a low-severity bug.
// 03 The gadget-chain concept
The mechanism behind deserialization RCE is the gadget chain, and it's worth understanding because it explains why patching libraries matters so much. A gadget is a piece of existing, legitimate code — a class with a method that does something mildly useful during deserialization. On its own it's harmless. A gadget chain links several of these together, through a carefully crafted serialized object, so that deserializing it triggers gadget after gadget until the sequence reaches a harmful action like command execution. The individual pieces are your own code and your dependencies; the exploit is the choreography. Crucially, public tooling maintains libraries of known gadget chains for popular frameworks — so an app that deserializes untrusted data using common libraries can be exploited with off-the-shelf chains, no custom research required. That's why “we don't have known-vulnerable code” misses the point: the gadgets live in the libraries everyone uses.
// 04 Where it appears — across languages & hidden spots
Java & .NET
Native object serialization — the classic, high-impact home of gadget-chain RCE.
Python & PHP
pickle and PHP unserialize() — equally dangerous with untrusted input.
Hidden carriers
Serialized data in cookies, tokens, view state, caches and message queues.
APIs & uploads
Endpoints accepting serialized payloads, and imported object files.
The finding is often invisible from the outside because the serialized blob hides in a cookie or token that looks opaque. A tester decodes those blobs, recognises the serialization format, and probes whether attacker-controlled objects are accepted — exactly the manual work a scanner can't do.
// 05 How to test and fix it
Testing: identify where the app deserializes data — decode cookies, tokens and API payloads and look for recognisable serialization formats (Java's markers, PHP's O:, Python pickle, .NET). Where untrusted serialized data is accepted, attempt a known gadget chain for the framework and confirm impact carefully in a controlled way. Fixing follows a clear hierarchy: best, don't deserialize untrusted data at all — use simple, data-only formats like JSON with a safe parser instead of native object serialization. Where native serialization is unavoidable: allow-list the permitted types, add integrity checks (sign the serialized data so tampering is detected), run deserialization with least privilege, and keep libraries patched since new gadget chains are found and fixed over time. Input filtering alone is unreliable — the safe design choices remove the capability, whereas filtering tries to catch every payload. It's a priority check in every web app engagement, per our methodology.
// 06 Frequently asked questions
What is insecure deserialization?
Serialization converts an object to bytes; deserialization rebuilds it. Insecure deserialization arises when an app deserializes untrusted data without validation. Because serialized data describes objects and can trigger code during reconstruction, an attacker who controls the input can manipulate logic or achieve remote code execution — turning a data operation into an execution primitive.
Why is it so dangerous?
It frequently leads to remote code execution, often from a single crafted input and without credentials. In Java, .NET, Python and PHP, deserializing attacker data can invoke methods during reconstruction, and attackers chain existing classes (a gadget chain) to reach command execution — full server compromise. Even without RCE it enables auth bypass, privilege escalation and data tampering.
What is a gadget chain?
A sequence of existing classes and methods in the app or its dependencies that an attacker links together, via a crafted serialized object, to reach a harmful action like command execution. The gadgets are legitimate code; the attack is the choreography during deserialization. Public tools maintain libraries of known chains for common frameworks, so vulnerable apps are at real risk without custom exploits.
How do you prevent it?
Best: don't deserialize untrusted data — prefer JSON with a safe parser over native serialization. Where unavoidable: allow-list permitted types, add integrity checks (sign the data), run with least privilege, and keep libraries patched. Input filtering alone is unreliable because safe design removes the capability while filtering tries to catch every payload.
// 07 Related reading
- XXE injection explained — another parser-driven, high-impact class.
- OWASP Top 10 in real engagements and mass assignment.
- Web application penetration testing and source code review.