Deserializing data a stranger controls
Some deserializers rebuild an object by running code as they read it. Point one at bytes an attacker controls and you have handed them remote code execution, no injection characters required.
What can go wrong
Unsafe deserialization means turning attacker-controlled bytes back into objects with a format that can carry executable behavior. The dangerous part is not parsing the data. It is that rebuilding certain objects runs their code.
The APIs that do this, by language:
- Python
pickle.loads, andyaml.loadwithoutSafeLoader - Ruby
Marshal.load - PHP
unserialize - Java
ObjectInputStream.readObject - .NET
BinaryFormatter
If any of these reads a request body, a cookie, an upload, or a queue message that a stranger can shape, the stranger chooses which objects get built and what runs during the rebuild.
It happened for real
Rails accepted YAML in request parameters and passed it to a parser that instantiated arbitrary Ruby objects: unauthenticated RCE on essentially every Rails app of the era, driven by a plain HTTP request with a changed Content-Type (Rapid7 on CVE-2013-0156). Metasploit shipped a module and the bug was mass-exploited (Exploit-DB 24019).
How to check yours
Seatbelt flags this automatically. A request value reaching one of these deserializers is a must-fix hard gate. It is a repo-lane, multi-language check: a client bundle never does this, so it is read from your source, not inferred from the outside.
Ask your agent: "Find every call to pickle.loads, Marshal.load, unserialize, ObjectInputStream.readObject, BinaryFormatter, or yaml.load without SafeLoader. For each, say whether the input can come from a request, cookie, upload, or queue message."
Manual check: Search for those API names. Trace each input back to its source. Any path from the network to one of these calls is exploitable.
Fix direction
Do not deserialize request data with these APIs. Use a data-only format (JSON), the safe loader for your language (yaml.safe_load, SafeLoader, an allowlist of permitted classes), or verify a signature on the blob before you deserialize it.
Paste into your agent: "Replace unsafe deserialization of any request-reachable input with JSON parsing or the language's safe loader. Where a binary format is required, add signature verification before the deserialize call. Show each call site before and after."