nullifAI: Malicious Pickle Models Evading Hugging Face Scanning
Two models on Hugging Face carried reverse-shell payloads in broken Pickle files, deliberately malformed and 7z-compressed to slip past Picklescan. Loading the model opened a connection back to the attacker — RCE via the model artifact itself.
What happened
In February 2025 ReversingLabs identified a novel technique they dubbed nullifAI on Hugging Face. Two models were stored in PyTorch format — a compressed Pickle — but packed with 7z instead of the usual ZIP, and the Pickle streams were deliberately broken. The malformation was enough to slip past Picklescan, the platform’s primary scanner, while the malicious opcodes near the start of the stream still executed on deserialization.
The payload was a reverse shell: loading the model opened a network connection back to an attacker-controlled host, handing over code execution on whatever machine imported it. Both artifacts resembled proof-of-concepts and were deactivated by Hugging Face, but the technique showed that scanner coverage of the Pickle format is far from complete.
Why it maps to ATLAS
- AML.T0010.003 — AI Supply Chain Compromise: Model: the attack rides the model-distribution supply chain.
- AML.T0058 — Publish Poisoned Models: malicious models are published to a public hub.
- AML.T0011.000 — User Execution: Unsafe AI Artifacts: deserializing the Pickle model executes attacker code.
Detection notes
Pickle is executable code, not data — treat any Pickle-format model as untrusted software.
The evasion here was format-level (7z packaging + broken stream), so signature scanning alone
missed it; inspect Pickle opcodes for REDUCE/GLOBAL calls into os/subprocess, and
load unknown models in a sandbox with no network so a reverse shell has nowhere to go. Prefer
safetensors wherever possible.
Detection
Log sources
- Model provenance / scanner (Picklescan) results
- Process + network telemetry on model-load hosts
- Pickle opcode inspection (REDUCE / GLOBAL to os/system)
Signals
- PyTorch artifacts compressed with 7z instead of ZIP
- Broken/truncated Pickle that still executes on partial deserialization
- Outbound connection immediately after model load
Mitigations
- Prefer safetensors; avoid loading untrusted Pickle-format models
- Load models in a sandbox with no egress; scan opcodes, not just signatures
- Pin + verify model provenance; treat model files as executable code