Insecure Deserialization: From Serialized Blob to Remote Code Execution
Deserialization to Memory Corruption
When the deserializer is native code: type confusion and buffer issues in parsers, why it matters even in memory-safe languages, and realistic expectations.
Published
Most deserialization bugs give object injection and RCE through gadgets, but there is a second, lower-level class: when the deserializer itself is native code, malformed input can corrupt memory. This page covers what that means, why it reaches even safe languages, and how to set realistic expectations. Practice on a free live target.
When the deserializer is native
The object-injection attacks elsewhere in this cluster abuse the deserializer working correctly. Memory corruption is the opposite: the deserializer working incorrectly on malformed bytes. When the parser is written in C or C++ (many binary-format and native-extension parsers are), a crafted length field, a recursive structure, or an unexpected type can drive an out-of-bounds read or write, a type confusion, or an integer overflow in the parsing code.
Type confusion and buffer issues
Two common shapes:
- Type confusion: the serialized data claims one type, and the native code processes it as another, so a field is interpreted as a pointer or a size it is not. That mismatch can lead to arbitrary read or write.
- Buffer issues: a length prefix that does not match the actual data, or a deeply nested structure, overruns a buffer or exhausts the stack.
These are the same bug classes as in any native parser, reached through the deserialization entry point.
Why it matters even in memory-safe languages
Python, Ruby, PHP, and Node are memory-safe in their own code, but they call native extensions for speed, and those extensions are not. A deserializer or parser implemented in C, invoked from a safe language, can still corrupt memory on malformed input. The safe layer cannot protect what happens inside the native call, so the risk is real wherever a managed app hands untrusted bytes to a native parser.
Realistic expectations
Calibrate what a finding here actually means:
Most common a crash on malformed input -> denial of service
Harder a controlled out-of-bounds write -> potential code execution, target-specific
Rare in practice a clean, reliable RCE primitive from a web-facing deserializerModern mitigations (ASLR, stack canaries, heap hardening) make turning a memory bug into controlled execution difficult and specific to the build. A reproducible crash is a legitimate, serious finding on its own.
When to stop and report
Memory-corruption work has a different risk and authorization profile than object injection. If you reach a crash on malformed serialized input:
- Document the reproducer (the exact input, the crash, the component) and treat it as a DoS finding.
- Do not attempt exploitation beyond a crash unless your engagement explicitly authorizes memory-corruption and binary exploitation.
- Do not over-claim. A crash is not RCE. Report what you proved.
Where this sits in the cluster
This is the edge of deserialization testing for most web work. The high-value, repeatable attacks are object injection and gadget chains in the other spokes. Native memory corruption is worth recognizing, worth reporting when you trip it, and usually worth handing to a specialist rather than chasing into full exploitation on a web engagement.
For the mainstream techniques, return to magic methods and gadget chains, and for safe-by-default defenses see preventing insecure deserialization. Ready to practice the exploitable classes? Sign up free and try it.
← Back to Insecure Deserialization: From Serialized Blob to Remote Code Execution