Security Digest · Feb 27, 2024 · Malicious package · AI / LLM
Malicious Hugging Face Models: Pickle Code Execution
JFrog found ~100 Hugging Face models with code that runs on load, one opening a reverse shell. No CVE or patch: use safetensors and weights_only loading.
Our verdict
Check exposure
This is a standing risk, not a one-off bug: loading a pickle-based model from an untrusted repo is running that author's code, so check how your pipelines load third-party weights.
Who must act: Teams and researchers that download PyTorch .bin/.pt/.pkl or Keras models from arbitrary Hugging Face accounts and load them with full pickle deserialization, especially on machines holding credentials.
Who can relax: People who only load safetensors weights or models from organizations they trust, and who run PyTorch 2.6 or later with the default weights_only=True loading.
- Affected
- Any environment that deserializes untrusted pickle-based model files (for example torch.load with weights_only=False, pickle.load, joblib)
Keras/TensorFlow models from untrusted sources (JFrog also found malicious models in these formats) - Fixed in
- No patch: mitigations are safetensors, torch.load(weights_only=True) (the default since PyTorch 2.6), and trusted sources
- CVSS
- Not scored
- EPSS
- n/a
- CISA KEV
- Not listed
- Exploitation
- Exploited in the wild
- Severity
- High
What to do
- Inventory where your code loads third-party models and which formats it uses.
- Prefer safetensors weights; refuse .bin/.pt/.pkl files from unknown authors.
- Upgrade to PyTorch 2.6 or later, or pass weights_only=True explicitly; never set weights_only=False on files you did not produce.
- Check the Hub's pickle import scan results on a file before downloading it, and treat flagged imports (exec, eval, os, subprocess, socket) as malicious.
- Load unvetted models only in an isolated sandbox with no credentials and restricted network egress.
How to check if you are affected or compromised
- Statically list a pickle's imports without running it, for example python3 -m pickletools model.pkl, or use fickling, and look for os, subprocess, socket, builtins.exec or eval.
- Search your Hugging Face cache (~/.cache/huggingface/hub) and artifact stores for models from the accounts JFrog named (baller423, star23).
- Review egress logs for connections to 210.117.212.93:4242 or 136.243.156.120:53252 (the reverse-shell endpoints JFrog reported).
What happened#
On February 27, 2024, JFrog researcher David Cohen reported finding "around 100" malicious models on the Hugging Face Hub, after excluding false positives. The models were caught by a JFrog scanner that checks new uploads several times a day. JFrog said PyTorch models were the most common, followed closely by TensorFlow/Keras.
The standout was a PyTorch model uploaded by a new account as baller423/goober2, which was later deleted. Its payload was planted with Python's pickle __reduce__ method, so it ran when the file was deserialized. When JFrog decompiled it with the fickling tool, it opened a reverse shell to 210.117.212.93 on port 4242. JFrog traced the IP to KREOnet, a South Korean research network, and said that could point to researchers rather than criminals. A similar model, star23/baller13, connected to 136.243.156.120 on port 53252 and was still live when JFrog published. A honeypot JFrog set up received a connection but no commands.
No CVE was assigned, because this is not a bug in one product. Pickle, the default format for PyTorch weights, is designed to be able to run code during loading. Hugging Face's own documentation describes loading a pickle file as an opening for arbitrary code execution attacks.
Who is affected#
Anyone who downloads a model from an account they don't know and loads it with full pickle deserialization. That covers torch.load with weights_only=False, plain pickle.load, and tools that wrap them. JFrog also flagged Keras/TensorFlow models, so pickle is not the only risky format. The code runs with the permissions of whoever loads the model. On a data scientist's laptop or a GPU training box, that usually means cloud keys, Hugging Face tokens and source code.
Do you really need to act?#
For most teams this is a hygiene issue, not an emergency. JFrog found about 100 bad models in a very large catalog. The risk is concentrated in people who browse for niche or newly uploaded models and run them as is.
The defaults have improved since 2024. PyTorch's serialization notes say that starting in version 2.6, torch.load uses weights_only=True when no custom pickle module is passed. PyTorch adds that this reduces but does not eliminate risk, since denial of service and possibly memory corruption remain. Error messages still invite users to switch to weights_only=False for older checkpoints, which "can result in arbitrary code execution." That is the step to watch for in your code.
Don't rely on the Hub to catch everything. Hugging Face scans every pushed file with ClamAV and a pickle import scan, and highlights suspicious imports. Its documentation says plainly that this is "not 100% foolproof." JFrog noted that flagged models could still be downloaded.
What to do now#
- Find every place your code or notebooks load third-party models, and record the format (
.safetensors,.bin,.pt,.pkl,.h5/.keras). - Prefer safetensors, which JFrog describes as a format Hugging Face built for storing model data safely. Hugging Face also suggests loading only from trusted users and organizations and checking signed commits.
- Check your PyTorch version with
pip show torch. Upgrade to 2.6 or later, or passweights_only=Trueexplicitly. Search your code forweights_only=False. - Before downloading, look at the import list the Hub shows for pickled files. Imports such as
exec,eval,os,subprocessorsocketare red flags. - Load anything you haven't vetted in a sandbox with no secrets and limited outbound network access.
How to tell if you were hit#
- Inspect pickles without executing them, for example with
python3 -m pickletools file.pklor Trail of Bits' fickling. Look forGLOBAL/STACK_GLOBALimports of dangerous functions followed byREDUCE, the opcode pattern Hugging Face describes. - Search
~/.cache/huggingface/huband internal model registries for repos fromballer423orstar23. - Check egress and EDR logs for connections to 210.117.212.93:4242 or 136.243.156.120:53252. If you find one, rotate every credential on that host.
Timeline#
- — JFrog publishes its findings on roughly 100 malicious Hugging Face models.
- — As of publication,
star23/baller13was still live, and Hugging Face had blocked another star23 model after user reports. - — No CVE assigned. PyTorch defaults to
weights_only=Truefrom version 2.6.
Sources
Original sources first: vendor and project advisories, CVE and government records, the discoverers’ write-ups. Every claim above links to one of these. See how the Security Desk works.