thesecguy/poc-npy-modelscan-bypass
0
Defensive PoC: NumPy .npy with object dtype -- ProtectAI / HuggingFace pickle scanner bypass
Do not load this file in production. This is a real ACE payload (writes sentinel /tmp/PWNED_BY_NPY).
What it shows
numpy.save(path, np.array([obj], dtype=object), allow_pickle=True) produces a .npy file that starts with the magic bytes \x93NUMPY and embeds an object array as a pickle inside the body. ProtectAI modelscan does not recurse into the embedded pickle for .npy; it sees the NPY magic, classifies the file as a plain numerical array, and returns "No issues found".
numpy.load(path, allow_pickle=True) unpickles the embedded payload, executing arbitrary code via __reduce__. allow_pickle=True is required by every numpy caller that handles object arrays -- common in datasets/checkpoints from older codebases, sklearn, gym/stable-baselines, etc.
Reproduce
pip install numpy modelscan
modelscan -p poc.npy # No issues found!
python3 -c "import numpy as np; np.load('poc.npy', allow_pickle=True)"
ls /tmp/PWNED_BY_NPY # sentinel