Skip to main content

Insecure Deserialization

Insecure deserialization rebuilds objects from untrusted data using mechanisms that can instantiate arbitrary types, enabling remote code execution and DoS. Use data-only formats like JSON, restrict deserialization to allowlisted types, and validate the result.

Insecure deserialization is the act of reconstructing objects from untrusted, attacker-influenced data using mechanisms powerful enough to instantiate arbitrary types and invoke their logic during the process. Many languages' native serialization (Java's ObjectInputStream, Python pickle, Ruby Marshal, PHP unserialize, .NET BinaryFormatter) will build whatever the byte stream describes — including dangerous "gadget" object chains — turning a data parse into code execution.

Why It Happens

Native serialization is convenient: it round-trips complex object graphs in one call, ideal for caching, session storage, queues, and inter-service messaging. Developers reach for it without realizing the input might be attacker-controlled (a cookie, a cache entry, a message). Polymorphic deserialization features that embed type information in the data are enabled for flexibility, which is exactly what attackers exploit.

Why It Hurts

When the deserializer can instantiate arbitrary classes, an attacker crafts a payload that, as it is reconstructed, triggers a chain of method calls (a gadget chain) leading to remote code execution — full system compromise. Even without RCE, attackers cause denial of service (billion-laughs, deeply nested objects), object injection that subverts application logic, or authentication bypass by forging serialized session objects. These bugs are severe and have produced critical CVEs across ecosystems.

Warning Signs

  • Code deserializes data that originates from clients, cookies, caches, or messages using native binary serializers.
  • BinaryFormatter, pickle.loads, Marshal.load, unserialize, or ObjectInputStream is fed external input.
  • Deserialization preserves arbitrary types from the data (polymorphic handling enabled).
  • Library advisories flag deserialization gadget chains in dependencies.

Better Alternatives

Avoid native object serialization for untrusted data. Use simple data-interchange formats — JSON, Protocol Buffers, MessagePack — that describe data, not code, and map them into known types you control. If polymorphism is needed, restrict deserialization to an explicit allowlist of permitted types rather than honoring type info from the payload. Validate the resulting data against a schema. Apply integrity protection (signed/MAC'd) to any serialized data that must round-trip through a client, and run with least privilege to contain impact.

How to Refactor Out of It

  1. Find every deserialization of externally influenced data, including caches and message queues.
  2. Replace native serializers with data-only formats (JSON/Protobuf) deserialized into fixed, known types.
  3. Where native serialization must remain, configure a strict type allowlist and disable arbitrary polymorphic resolution.
  4. Validate deserialized objects against a schema before use.
  5. Sign or MAC any serialized data that crosses a trust boundary, and verify before deserializing.
  6. Patch libraries with known gadget chains and add tests using malicious payloads.