Unsafe pickle deserialization in deluca load paths enables arbitrary code execution (CWE-502)
- Dominant language
- Jupyter Notebook
- Stars
- 126
- Forks
- 17
- PR merge metrics
- No merged PRs in 30d
Description
Multiple code paths in `deluca` pass attacker-controlled file contents to `pickle.load()`. Python's `pickle` is not a safe data format: during deserialization it can execute arbitrary Python code via mechanisms such as `__reduce__` and `__setstate__`.
As a result, loading a malicious `.pkl` file through any of the affected APIs results in arbitrary code execution in the context of the user running the Python process.
## Affected code paths
- `deluca/core.py:44` - `deluca.load(path)`
- `deluca/lung/utils/data/analyzer.py:34` - `Analyzer(path)`
- `deluca/lung/utils/data/breath_dataset.py:35` - `BreathDataset.from_paths([...])`
- `deluca/lung/utils/scripts/test_simulator.py:42` - `test_simulator(..., dataset="artifact.pkl")`
Tested against commit `e483d2f13cd0ee15784ac3f34b82bfeecc47f115`.
## Impact
An attacker who can deliver a malicious pickle artifact (shared dataset, checkpoint, benchmark file, saved experiment result, Hugging Face–style artifact, etc.) to a Deluca user achieves arbitrary code execution as that user the moment the file is loaded through a normal workflow.
No prior access to the victim host, authentication, network exposure of a Deluca service, or elevated privileges is required.
In ML and research environments - where serialized datasets, checkpoints, and experiment outputs are routinely exchanged between collaborators and pulled from third-party sources this attack scenario is realistic. Post-exploitation consequences include reading local files, exfiltrating SSH keys / API tokens / cloud credentials, tampering with experiments or model artifacts, and pivoting into shared research infrastructure or CI pipelines.
## Root cause
Each affected call site invokes `pickle.load()` (or equivalent) directly on a user-supplied path with no allow-list of permitted classes, no restricted unpickler, and no warning to the caller that the operation is unsafe.
## Suggested fix
A minimal, merge-friendly mitigation:
1. Centralise pickle loading in a single helper in `deluca/core.py`.
2. Have the helper emit a `UserWarning` explaining that the operation is unsafe, unless the caller explicitly passes `trust_source=True`.
3. Update the four affected call sites to go through the helper and propagate the `trust_source` flag.
4. Document the risk in the public API docstrings so downstream users understand that untrusted artifacts must not be loaded.
A more thorough fix - replacing pickle with a safe serialization format such as `safetensors` + JSON for model and dataset state - would be preferable but breaks backwards compatibility with existing Deluca checkpoints, so is intentionally out of scope for this initial patch.
A PR implementing the minimal mitigation will be opened and linked here.
## Reproduction
A safe, non-destructive proof-of-concept is available on request and will be included as a regression test in the linked PR. The PoC uses `print()` as the payload - no filesystem, network, or process side effects.
## References
- CWE-502: Deserialization of Untrusted Data
- Python docs - `pickle` module security warning: https://docs.python.org/3/library/pickle.html
Contributor guide
Assessment
This issue has not been assessed yet.