genai
SECURITY LAB
IncidentsSupply chain

~100 Backdoored Models Found on Hugging Face

High severityReal-world incidentFebruary 2024LLM04: Supply Chain
Status: Reported publicly; Hugging Face blocked the highlighted model, but its pickle scanner only labelled such files unsafe rather than blocking downloads
Sources checked October 2026
On this page

A model file is not inert data — with pickle, loading it can run code. About 100 on Hugging Face did.

WhenFebruary 2024
TargetHugging Face model hub / model users
ResearcherJFrog Security Research
TechniqueMalicious pickle __reduce__ → code execution on load
ImpactSilent backdoor / reverse shell on the victim's machine
Attack flow
  1. 1An attacker uploads a model whose pickle payload runs on deserialisation
  2. 2A data scientist loads the model with a normal torch.load
  3. 3The payload executes and opens a reverse shell on their machine
Try this attack in a live lab Open the lab

What happened

In early 2024, JFrog's scanning of Hugging Face identified roughly 100 malicious models that execute attacker code the moment the model is loaded. Most abused Python's pickle format (PyTorch's default serialisation), embedding a payload in the object's __reduce__ method; a highlighted case opened a reverse shell to a hardcoded address, with other repos pointing elsewhere. JFrog judged that many uploaders were probably researchers rather than criminals, but the shells connected to real IP addresses.

How the attack worked

Pickle deserialisation can run arbitrary code. A poisoned model is a normal-looking file that runs its payload during torch.load — before you ever run inference.

Root cause

Treating third-party model files as inert data. In an unsafe serialisation format, loading a model is executing untrusted code.

What a control would have caught

Scanning models for dangerous pickle opcodes before load, and loading only in a sandbox, catches this class — as does preferring a non-executable format.

How to prevent it

  • Prefer safetensors over pickle-based formats.
  • Scan and sandbox model loads; treat model files as untrusted code.
  • Pin and verify model provenance/hashes.

Feel it yourselfThe replay lab loads a backdoored model that triggers attacker behaviour — the malicious-model supply-chain class.

FAQ

How does loading a model run code?

PyTorch's default serialisation uses Python pickle, which can execute arbitrary code on deserialisation via the object's __reduce__ method. A poisoned model runs its payload the instant you load it.

What did the payloads do?

A highlighted case opened a reverse shell to a hardcoded address, giving the attacker control of the victim's machine; other repos pointed at different addresses. JFrog judged many uploaders to be researchers, but the shells reached real IPs.

How do you defend against it?

Prefer safetensors over pickle, scan models before loading (e.g. Picklescan), and treat third-party model files as untrusted code, not inert data.

Replay this attack
Load an untrusted pickle checkpoint and show that the load itself runs code — the malicious-model class JFrog found on Hugging Face.
Open the live lab
A live, sandboxed lab. It recreates the technique, not this exact product.