Back to Technical Mode

Insecure Deserialization

Serialization formats that encode an object's class alongside its data (Java's native serialization, Python's pickle, PHP's unserialize) let an attacker specify which class gets instantiated. If any reachable class has a side-effecting constructor or method, that's a gadget for remote code execution.

The vulnerability isn't the data being wrong — it's the deserializer being willing to instantiate whatever class the payload names
"Gadget chains" string together otherwise-harmless classes already on the classpath/import path to reach a dangerous sink (like file write or process execution)
Signing serialized data doesn't help if the signing key is the same secret shipped in every install, or if the check happens after deserialization instead of before
The strongest fix is avoiding native object serialization for anything crossing a trust boundary — use a data-only format (JSON) with an explicit schema instead

Want this flow explained in detail as it plays?

POST/api/session/restore

Headers

Host:app.flowground.dev
Content-Type:application/x-java-serialized-object

Body

Loading...

Quick-Insert Payloads

Defense in depth

  • Never deserialize untrusted input with a format that carries type/class information (native Java serialization, pickle, PHP unserialize, YAML with tags enabled) — use JSON with a strict schema instead
  • If a legacy format truly can't be replaced, deserialize inside a sandboxed process with an allowlist of the only classes that are legitimately expected
  • Treat serialized-object input from a client exactly like SQL or shell input: it is untrusted code, not untrusted data

Vulnerable vs. Fixed

import pickle

def restore_session(raw_bytes):
    return pickle.loads(raw_bytes)  # executes arbitrary code embedded in the payload