A cryptocurrency-mining campaign reported in Hugging Face model repositories used Python code that could run during model loading when trust_remote_code=True was enabled, according to Pluto Security’s analysis. Pluto described two waves of malicious repositories after first-wave accounts were removed. It dated a near-identical model copy to October 25, 2026; BleepingComputer reported on October 29 that it had examined the copy and found the same miner and a reverse shell.
How the campaign resurfaced
Pluto reported 31 core malicious repositories across seven Hugging Face accounts in two waves. It also counted 13 linked models separately. After Hugging Face and ModelScope removed first-wave accounts, Pluto said new accounts appeared within days. The reports concern specific repositories hosted on Hugging Face, not an intrusion into the platform’s infrastructure.
What the download totals counted
Pluto’s figures through October 28, 2026, add up to 32,376 downloads across the core repositories and linked models. The number counts downloads, not infected machines or unique users.
| Repository group | Repositories | Downloads | Time basis |
| First wave | 12 | 728 | Recorded before removal |
| Second wave | 19 | 29,090 | Through October 28, 2026 |
| Linked models | 13 | 2,558 | Through October 28, 2026 |
The two campaign waves account for 31 core repositories; adding 13 linked models brings the combined total to 44. The three download counts sum to 32,376, but they do not say how many people downloaded the models or how many hosts ran the code.
How repository code ran during model loading
With trust_remote_code=True, the loader can import a Python module specified by a model repository. Statements at the top level of that module run during import, before the model class is returned. Pluto said the campaign’s code therefore ran with the privileges of the process loading the model, before inference began.
In the analyzed MENXIANGYU/qwen2-tiny repository, Pluto reported that model.safetensors was just 42 bytes and contained no tensors. The malicious behavior was in the repository’s Python code, rather than in poisoned model weights or a pickle exploit. Pluto named self-hosted Xinference and GPUStack, rented GPU machines, shared research notebooks and CI jobs that pull test models among the environments the campaign targeted.
Persistence traces and variant-specific behavior
Pluto described a miner called syscore.bin that could launch from memory under the process name [kworker/u20:1]. In a representative build, a watchdog at /tmp/.cch/svc.py restarted a missing miner every 120 seconds, while shell startup hooks helped maintain persistence.
For a host investigation, Pluto listed /tmp/.cch/, unexpected svc.py activity, altered shell startup files, and a [kworker/u20:1] process with mining arguments as leads. Other checks include encoded qwen2-tiny- or ezv- registrations in Xinference and connections to campaign-related infrastructure. A missing individual indicator does not rule out compromise.
Some behaviors belonged to particular variants. Pluto said builds named qwen2-tiny-5, -6 and -9 opened reconnecting reverse shells to 212.32.253.3 on port 443 or 9443. It separately described MENXIANGYU/qa-whl-1021 as a script that could mount candidate host disks from a privileged container and gain root access on the underlying host. Those capabilities were not attributed to every repository.
What to do after loading a suspect model
Pluto recommends investigating a host even if model loading failed or GPU use looks normal. Its response sequence is:
- Isolate the host to limit further access.
- Preserve evidence, including process and network information, logs, caches and startup files. Check other systems that loaded the same repositories.
- Remove persistence and backdoors as well as the miner. Stopping the visible mining process alone does not address the other mechanisms Pluto described.
- Rotate credentials the process could reach, using a clean system.
- Rebuild from a trusted image if the host’s integrity cannot be established.