joblib + ProtectAI/modelscan bypass — defensive PoC
This repo hosts a proof-of-concept malicious joblib artifact for a disclosure to
the huntr.com Model File Vulnerability program.
Do not load this file in production. It is a real ACE payload, kept benign
(writes a sentinel file /tmp/PWNED_BY_JOBLIB_PoC).
What it shows
joblib.dump(obj, "x.joblib", compress=3) writes a zlib-compressed pickle. The
zlib magic byte (0x78) at offset 0 is not a valid pickle opcode, so
pickletools.genops -- which is what ProtectAI modelscan uses to walk
opcodes -- aborts early with a parsing error and reports "No issues found".
The actual payload survives because joblib.load(...) decompresses first, then
unpickles, so the RCE constructor (__reduce__) fires.
Reproduce
1pip install joblib==1.5.3 modelscan==0.8.8
2
3# 1) modelscan should incorrectly mark this as clean
4modelscan -p iris_classifier.joblib
5# ... No issues found! ...
6# ... Parsing error: at position 0, opcode b'x' unknown
7
8# 2) joblib.load runs the embedded payload
9python3 -c "import joblib; joblib.load('iris_classifier.joblib')"
10ls -la /tmp/PWNED_BY_JOBLIB_PoC
The same trick works with compress=('lzma',3), ('gzip',3), ('bz2',3),
('xz',3) and the default compress=9 -- every joblib compression mode bypasses
the pickle scanner, while raw .pkl and uncompressed .joblib are correctly
flagged.
Affected scanner / pipeline
protectai/modelscan (PyPI 0.8.8 -- latest at 2026-04-30)
- huggingface.co's automated model-file scan (powered by ProtectAI), which is
the gate for surfacing the "Detected Pickle imports" warning on a model card.
Disclosure
Reported via huntr.com.