---
title: "Never rebuild objects from untrusted data · Agent Wranglers"
url: https://agentwranglers.se/playbook/application-security/input-and-injection/unsafe-deserialisation
id: APS-8
level: Required
risk: takeover
updated: 2026-10-27
build: a2a6bdfed830
tokens: 795
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Never rebuild objects from untrusted data

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Input and injection](https://agentwranglers.se/playbook/application-security/input-and-injection.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: APS-8
- Level: Required
- Chapter: [Input and injection](https://agentwranglers.se/playbook/application-security/input-and-injection.md)
- Rule: Read untrusted data only as plain data, such as JSON. Never use formats that can rebuild code objects.
- Check: Search the code for `pickle.loads`, `yaml.load(`, `unserialize(`, `ObjectInputStream` and `BinaryFormatter`. No match reads data from outside. Change one byte of every signed cookie and hidden field. The server rejects it with a 400 and never a 500.
- Risk: An account or system taken over
- How: Avoid Python `pickle`, Java serialisation, PHP `unserialize` and YAML loaders that create objects. Use the safe loader, such as `yaml.safe_load`. Sign any data you send out and read back, such as cookies. Then [parse input once at the boundary](https://agentwranglers.se/playbook/architecture/data-shapes/parse-at-the-boundary.md) into typed objects.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### Python example

```python
# Bad: pickle and the full YAML loader can run code
data = pickle.loads(cookie_bytes)
data = yaml.load(body, Loader=yaml.Loader)
# Good: plain data only
data = json.loads(body)
data = yaml.safe_load(body)
```

### PHP example

```php
// Bad: unserialize can build any object
$cart = unserialize($_COOKIE['cart']);
// Good: plain data only
$cart = json_decode($_COOKIE['cart'], true, 16, JSON_THROW_ON_ERROR);
```

## Sources

- [OWASP Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html)

## Related rules

- TST-39 [Fuzz every parser of untrusted input](https://agentwranglers.se/playbook/testing/security-and-robustness/fuzz-parsers.md) in Testing
- ARC-53 [Parse input once at the boundary](https://agentwranglers.se/playbook/architecture/data-shapes/parse-at-the-boundary.md) in Clean code and architecture

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/application-security/input-and-injection/unsafe-deserialisation">Agent Wranglers application security playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Turn off external entities in XML](https://agentwranglers.se/playbook/application-security/input-and-injection/xml-entities.md)
- Next: [Block prototype pollution](https://agentwranglers.se/playbook/application-security/input-and-injection/prototype-pollution.md)
- [Input and injection](https://agentwranglers.se/playbook/application-security/input-and-injection.md)
