Deserialization is just turning stored or transmitted data back into objects your program can use. The catch is that some formats can encode instructions to construct objects, and constructing them can run code. When the data is something you wrote, that is fine. When it comes from a user, an attacker controls those instructions, so parsing their payload executes whatever they put in it.
The two loaders AI tools reach for
Python's pickle and PyYAML's full loader are the common culprits, because they are the examples that appear most in training data and both work perfectly on well-formed input. The assistant writes the familiar call, it parses correctly in the demo, and nothing signals that the same call becomes a foothold the moment the input is hostile.
# both of these can run code from a crafted payload import pickle obj = pickle.loads(request.data) import yaml config = yaml.load(request.data) # full loader
A YAML document can carry a tag that tells the full loader to call a callable while parsing, and a pickle stream can encode object construction that runs code. Either way, loading attacker-controlled bytes is enough. The concept in full is in what insecure deserialization is.
Want to see exactly what Prbl flags? Watch it scan a demo app, no repo or account needed.
See a live scan →The fix: use a data-only loader
Never deserialize untrusted input with something that can execute code. For YAML, call yaml.safe_load, which only builds plain data types. For data interchange in general, prefer JSON. Never unpickle data you did not create, because pickle has no safe mode for untrusted input.
# YAML: the safe loader builds only plain data import yaml config = yaml.safe_load(request.data) # interchange: JSON carries no code-construction behavior import json obj = json.loads(request.data)
The change is small and the exposure disappears, because a data-only loader has nothing for the payload to hijack. The full walkthroughs are in the fixes for unsafe YAML deserialization and insecure pickle deserialization.
Frequently asked questions
Why does loading data run code at all?
Because some serialization formats encode more than values. They can encode instructions to construct objects, which may call code as part of rebuilding them. Python's pickle and PyYAML's full loader both do this. When the data is trusted, that power is convenient. When the data comes from a user, the attacker controls those instructions, so parsing their payload runs whatever they chose. The bug is using a code-capable loader on input you do not control.
Is yaml.load really dangerous if I only parse config files?
On truly trusted config on disk that you wrote, the risk is low. The problem is that the same call often ends up on paths that read user input, like an import feature or a request body, and there it becomes remote code execution. Because the fix is free, switching to yaml.safe_load everywhere is the safer habit than trying to track which call sites are trusted.
What is the safe alternative?
Use a data-only format and loader. For YAML, call yaml.safe_load, which only produces plain types like dicts, lists, strings, and numbers and cannot construct arbitrary objects. For data interchange in general, prefer JSON, which carries no code-construction behavior. Never unpickle data you did not create yourself, since pickle has no safe mode for untrusted input.
How would an attacker even reach this?
Anywhere your app turns external bytes into objects: a request body, an uploaded file, a message from a queue, a cookie or token that stores a serialized object. If any of those feed a code-capable loader, a crafted payload runs on your server. The tell to look for is pickle.loads or yaml.load, or any deserializer, sitting on data that originated outside your own code.
Find code-capable loaders on untrusted input
A deserializer sitting on request data has a recognizable shape, and a scan flags it with the file and line, so you can switch to a safe loader before the payload arrives. Run a free scan and see whether anything in your app deserializes input unsafely.