Security
lodum is designed with a secure-by-default philosophy. This document describes the security model, built-in protections, and guidelines for safe usage.
Threat Model
lodum deserializes data that may come from untrusted sources. The primary attack surface is during deserialization (the load() / loads() functions across all format modules), where maliciously crafted input could attempt:
- Arbitrary code execution
- Denial of service (stack exhaustion, memory exhaustion)
- Unauthorized access to system resources
Serialization (dump() / dumps()) is considered low-risk, as it only reads Python objects that the application code has already constructed.
SafeUnpickler (Pickle Module)
Pickle is inherently unsafe for untrusted data — a crafted pickle can execute arbitrary code during deserialization. lodum.pickle mitigates this risk with a SafeUnpickler that enforces a multi-layer allowlist approach.
How SafeUnpickler Works
SafeUnpickler lives in src/lodum/pickle.py and applies three layers of defense:
1. System Module Blocklist
if "os" in module_name or "sys" in module_name or "subprocess" in module_name:
raise pickle.UnpicklingError(f"Unsafe module '{module_name}' is forbidden.")
Any attempt to unpickle objects from dangerous modules (os, sys, subprocess, and any module containing these names) is rejected immediately.
2. Builtins Allowlist
When a class comes from builtins, it is only permitted if it is one of the following safe types:
| Allowed Types |
|---|
int, float, str, bool, bytes, bytearray |
list, tuple, dict, set, frozenset |
complex, NoneType, type |
Any other builtins name (including eval, compile, __import__) is rejected.
3. Known-Safe Library Types
A small set of standard library types from collections and array are explicitly permitted:
collections.defaultdict,OrderedDict,Counterarray.array,_array_reconstructor
4. Lodum-Enabled Class Allowlist
For classes from arbitrary third-party modules, SafeUnpickler checks for the _lodum_enabled attribute — a marker set by the @lodum decorator at import time. Only classes explicitly decorated with @lodum can be unpickled from external modules.
This means:
- If you decorate a class with
@lodum, it can be safely pickled and unpickled. - If someone sends you a pickle containing an arbitrary
os.systemcall or a random application class,SafeUnpicklerwill reject it.
Usage
import lodum.pickle as pickle
# Safe: deserializes only @lodum-enabled objects
obj = pickle.load(MyLodumClass, pickle_bytes)
Input Size Limits
All format modules enforce a maximum input size to prevent memory exhaustion from oversized payloads:
DEFAULT_MAX_SIZE: 10 MB (10 * 1024 * 1024bytes)- Applied to string and bytes inputs in
json,yaml,toml,msgpack,cbor,bson, andpicklemodules.
from lodum.core import DEFAULT_MAX_SIZE # 10485760
# Custom limit
obj = json.load(MyClass, data, max_size=5 * 1024 * 1024) # 5 MB
Recursion Depth Limits
To prevent stack exhaustion from deeply nested data:
DEFAULT_MAX_DEPTH: 100 levels- Enforced during both serialization and deserialization at every level of object traversal.
The limit is checked in the compiled dump/load handlers via the generated bytecode, providing efficient O(1) per-level cost.
exec() Code Generation
lodum uses Python's compile() (not exec()) to compile generated AST nodes into bytecode functions for each @lodum-decorated class. While this is safer than string-based exec(), there are still considerations:
Why It Is Safe
- Trusted source: The AST is generated from type hints defined in your application code at import time, not from external data.
- Compile, not exec: The generated code is compiled into a code object and stored in the context cache. It is only executed when called as a function, not at generation time.
- Stack depth protection: Every compiled handler includes a recursion depth check before processing nested structures.
Recommendations
- Do not decorate classes that are constructed from untrusted input or user data.
- Do audit your
@lodum-decorated classes as part of your code review process. - Do deploy in environments with restricted execution policies that permit
compile()(this is standard and built into Python).
JSON Schema Generation
The lodum.schema() function generates JSON Schema (Draft 2020-12) descriptions for @lodum classes. Schema generation is read-only — it inspects type hints and field metadata, does not execute arbitrary code or deserialization logic. It is safe to use on any data.
Reporting Security Issues
If you discover a security vulnerability in lodum, please report it responsibly:
- Do not open a public GitHub issue.
- Email zopemaven@gmail.com with details.
- Allow time for a fix before public disclosure.
We aim to acknowledge reports within 48 hours and release patches within 7 days for critical issues.
Security Changelog
| Date | Version | Description |
|---|---|---|
| 2026-02-11 | 0.2.0 | Initial SafeUnpickler with multi-layer allowlist in lodum.pickle. |
| 2026-02-21 | 0.3.0 | Input size limits (DEFAULT_MAX_SIZE) and recursion depth limits (DEFAULT_MAX_DEPTH) added to all format modules. |