Insecure Deserialization: How a Saved Object Turns Into Code Execution
2026-10-14 · 7 min read
Figure 1: Trusting serialized input is the root of the problem
Why this one is dangerous
Most injection bugs need the attacker to smuggle something past a filter. Insecure deserialization is quieter. The application willingly rebuilds whatever object it is handed, and in several popular languages that act of rebuilding can run code all by itself. No broken login, no missing patch, just data that the app trusted a little too far.
It has sat on the OWASP list for years, now folded into Software and Data Integrity Failures, and it keeps showing up in real breaches. Here is the mechanism, in plain terms.
Serialization in one paragraph
Serialization turns a live object into a flat form such as bytes or a string, so it can be saved to disk, cached, or sent across a network. Deserialization is the reverse: take that flat form and bring the object back. Session data, API payloads, cached values and message queues all lean on it constantly, and most of the time it is perfectly ordinary.
The risk appears when the flat form comes from somewhere the attacker controls, like a cookie, a form field or an upload.
Why rebuilding can run code
Here is the part that surprises people. In many languages the serialized form does not just hold values. It also records which class each object belongs to, and the language may call special methods on that class as it reconstructs the object. Those hooks exist for good reasons, such as reopening a database handle, but they run during deserialization before your own code gets a say.
If an attacker can name the class and set its fields, they get to pick which of those hooks fire and with what data. String enough of these built-in behaviors together, drawn from the libraries already on the server, and the result can be file writes, network calls or full command execution. The attacker never ships their own program. They borrow pieces that are already present.
A short way to see the idea is Python. Loading a pickle can trigger a method whose only job is to describe how to rebuild the object, and that description can be an instruction to run a shell command. That is why the Python docs warn, in bold, never to unpickle data you do not trust.
The same pattern across languages
- PHP rebuilds objects with
unserialize(), and attacker-controlled input here is the classic route to object injection through magic methods like__wakeupand__destruct. - Java native serialization starts with the bytes
0xAC 0xED, andreadObjecthas been behind a long run of remote code execution reports. - Ruby has the same shape through
Marshal.load. - Python pickle is the textbook case described above.
Each language differs in detail, but the lesson is identical: do not reconstruct objects from input you cannot vouch for.
Inspect without running
When you receive a serialized blob and want to know what it contains, the safe move is to read its structure rather than load it, because loading is the dangerous step. KeyDecryptor does exactly that in the browser, with nothing executed:
- PHP Serialize / Unserialize viewer shows the data as plain JSON.
- Java Serialized Object decoder walks the
0xACEDstream into a readable tree. - Ruby Marshal decoder turns Marshal data into JSON.
- Pickle disassembler lists the opcodes and flags the risky ones.
- Pickle / ML model scanner statically checks pickle and model files, which matters because many machine learning formats are pickles in disguise.
Reading a blob this way tells you what it is without handing control to it.
How to shut the door
- Do not deserialize untrusted input. This is the whole fix when you can manage it.
- Prefer data-only formats such as JSON, parsed into known fields, over native object formats.
- If you must accept a native format, restrict it to an allowlist of safe classes.
- Sign serialized data you control and reject anything whose signature fails, so tampering never reaches the parser.
- For machine learning, favor formats like safetensors over pickle-based checkpoints from strangers.
The bottom line
Insecure deserialization is less about a clever payload and more about misplaced trust. An app that rebuilds objects from input an attacker can shape is handing over a lever it did not mean to give. Keep untrusted bytes away from object reconstruction, inspect unknown blobs instead of loading them, and the whole class of bug mostly disappears.