nullifAI: how two malicious models slipped past Hugging Face's scanner using a compression trick
In February 2025, ReversingLabs researchers disclosed a technique they called nullifAI: a way to get a malicious PyTorch model onto Hugging Face, past the platform's own Picklescan security scanner, without tripping a single alert. The models — published under the names glockr1/ballr7 and who-r-u0000/0000000000000000000000000000000000000 — weren't sophisticated in their payload. What made them notable was how ordinary the evasion was: a file-format mismatch that a scanner built around one assumption simply wasn't built to catch.
Why pickle was the wrong format to trust in the first place
PyTorch models are commonly saved using Python's pickle serialization format, and pickle has a well-known property that makes it a poor fit for distributing untrusted files: deserializing a pickle stream doesn't just reconstruct data, it can execute arbitrary code as a side effect of reconstruction. A pickle file can embed instructions that run the moment pickle.load() touches them, unrelated to whatever object the file claims to represent. This is why loading a pickle file from an unknown source has long been treated by security-conscious engineers the same way you'd treat running an unknown executable — because, in effect, it is one.
Hugging Face knows this, which is why it runs Picklescan against uploaded model files: an automated check that inspects pickle streams for suspicious opcodes and flags anything that looks like it's trying to import dangerous modules or call dangerous functions. It's a reasonable mitigation for the obvious version of the problem. What ReversingLabs found is that it isn't hard to make the file the scanner sees diverge from the file PyTorch actually loads.
The trick: compress it wrong, on purpose
The two malicious models were valid pickle files, but instead of being compressed with the standard ZIP format PyTorch's serialization normally uses, they were compressed with 7z. Picklescan expected ZIP-compressed pickle data and, faced with a 7z-compressed file, couldn't parse it — and appears to have failed silently or inconclusively rather than flagging the mismatch as suspicious in itself. Meanwhile, the actual malicious payload was placed at the start of the pickle stream, structured so that it executed during deserialization before the rest of the stream (which may have been malformed or incomplete) caused any downstream failure. The code ran; the scanner never got far enough to see it.
The payload itself was a "platform-aware" reverse shell — meaning it selected its behavior based on the operating system it landed on — that connected out to a hardcoded IP address, 107.173.7.141, giving an attacker a foothold on any machine that loaded the model.
This is the pattern worth internalizing: the attackers didn't need to find a flaw in pickle's execute-on-load behavior, because that behavior is a documented, intended feature of the format. They needed to find a flaw in the scanner's assumption that every pickle file it needs to inspect will be packaged exactly the way the reference implementation packages it. A parser that only understands one container format is a parser with an unstated allowlist, and unstated allowlists are exactly where format-confusion attacks like this live.
Timeline and how it was handled
ReversingLabs reported the two models to Hugging Face's security team on January 20, 2025. Hugging Face removed them within 24 hours. ReversingLabs published its full technical writeup on February 6, 2025, naming the technique nullifAI.
It's worth being precise about what this incident was and wasn't. ReversingLabs itself characterized this as a proof-of-concept-level finding rather than evidence of an active, large-scale supply-chain compromise. There's no indication in the public reporting that these two models had significant download or usage numbers before removal, and no confirmed count of affected users or systems. This was a demonstration that the evasion technique worked, caught quickly once someone was specifically hunting for it — not a report of a campaign that got away from anyone.
That distinction matters for how seriously to weigh it, but it shouldn't be read as "not a big deal." A technique that defeats a purpose-built scanner using nothing more exotic than an alternate compression codec is cheap to reproduce, and the fact that one research team found it on a manual hunt is not evidence that it hasn't been used elsewhere, quietly, by someone who wasn't disclosing what they found.
What to check this week
- Don't rely on a single model-scanning vendor or method as your only gate. Picklescan is a genuinely useful control, but nullifAI shows that a scanner's blind spots become the attacker's path of least resistance — treat scanner "clean" results as one signal, not a verdict.
- Inventory where pickle-format models (
.pt,.pth,.binfiles using PyTorch's default serialization) enter your pipeline, whether pulled directly from Hugging Face, mirrored internally, or bundled into container images, and flag pickle as a format that executes code on load, not just data. - Prefer safetensors or other non-executable serialization formats where your framework and model source support them, since they store tensor data without the deserialization-time code execution risk pickle carries by design.
- Re-scan cached or previously-downloaded models, not just new pulls — a model cached before a scanner's blind spot was found offers no retroactive protection.
Why this keeps happening
nullifAI is one instance of a broader category: security tooling built for AI artifacts is new, narrower in scope than it looks, and frequently makes assumptions about file structure that attackers can falsify without needing zero-days. The interesting part of this incident isn't the reverse shell — reverse shells are unremarkable — it's that the defensive control specifically designed to catch this class of payload was defeated by a change to the container format around the payload, not the payload itself. Any scanning approach that inspects one layer of a file (the pickle opcodes) without first verifying the layer beneath it (the actual bytes on disk, however they're packaged) inherits this exact gap.
How Safeguard helps
Safeguard's AI-SPM capabilities are built around the recognition that model files are executable artifacts, not passive data, and that scanning them requires validating structure at every layer rather than trusting a single expected format. Safeguard's model-artifact scanning covers pickle, safetensors, GGUF, and ONNX formats specifically because each has different failure modes for smuggling code past a naive parser — a pickle stream wrapped in an unexpected container is exactly the kind of mismatch that layer-aware scanning is designed to surface rather than silently pass through. Combined with AI-BOM discovery that tracks where every model artifact in your environment actually came from, and continuous monitoring that re-checks cached and previously-approved artifacts rather than only inspecting them once at intake, the goal is to close the specific gap nullifAI exploited: a scanner that only understands the format it expects to see.