Fake "test" models on Hugging Face mined crypto on GPU servers — and a second wave followed the first takedown
Pluto Security found 31 Hugging Face repos whose custom code installs a crypto miner and backdoors when loaded with trust_remote_code. Downloads top 32,000; second-wave repos now disabled.
Update, November 5, 2026: Pluto's report listed the 19 second-wave repositories as live on October 28. When we re-checked on November 5, the second-wave repositories we looked at — MENXIANGYU/qa-whl-1021, MENXIANGYU/qwen2-tiny-9 and the near-identical copy htt0118/qwen2-tiny — showed "Access to this model has been disabled," citing Hugging Face's content policy. We did not check every repository, and Hugging Face has published no statement. Disabling a repository does not clean machines that already loaded it: the checks below still apply.
On October 29, 2026, Pluto Security published research on a cryptomining campaign it calls "Load/Mine": 31 malicious repositories on Hugging Face, plus a mirror on ModelScope, posing as small Qwen2 test models. Anyone who loaded one with custom model code enabled (trust_remote_code=True) ran the attacker's Python on their machine, which installed a cryptocurrency miner and, in some builds, a backdoor. If your team self-hosts models, especially with Xinference or GPUStack, check which repositories you loaded with custom code and review that code before allowing it again.
What happened, in plain English
Hugging Face is the largest public hub for AI models. Developers download models from it much as they download software packages from npm or PyPI. A model is mostly data (the "weights"), but some models also include a small Python file that tells the loading software how to build the model. Popular tools such as Hugging Face's Transformers library will only run that Python file if the user switches on a setting called trust_remote_code. It is off by default, but many tutorials and test scripts turn it on.
According to Pluto Security, the attackers uploaded tiny "test" models whose weights were harmless. The danger was entirely in the accompanying Python file. A setting in the model's configuration file (config.json) tells the loader which Python file to import, and code in that file runs the moment it is imported, before any weights are even read. So the attack happened during "loading", not when the model answered a question.
Once running, the code installed a cryptocurrency miner disguised as a normal Linux system process, set itself to restart automatically, removed competing miners, and in some versions added a reverse shell (a connection that lets the attacker type commands on your machine remotely) or planted an SSH key for logins. The targets were GPU (graphics processor) servers, which are valuable for mining.
Think of it as a free sample left on your doorstep that only works if you invite it inside — and then it moves into your spare room.
Pluto counted 32,376 downloads across the campaign and related repositories (29,818 for the campaign repositories alone), but stresses that downloads are not the same as confirmed infections.
Are you affected? What to do now
Most readers have nothing to do. You are only potentially affected if your organisation loads open models from Hugging Face or ModelScope and allows custom model code. Highest risk: self-hosted inference servers running Xinference (the primary target, per Pluto) or GPUStack (targeted by a container-escape script), and shared notebooks or CI jobs that pull small test models without anyone reading the code.
Check
- Search code, notebooks and configs for
trust_remote_code=True(and equivalent flags in your serving tools). List which model repositories were loaded that way. - Compare those repositories with the account and repository list in Pluto's report. Accounts named by Pluto include
dsxk4mr8tq,hhzz667,MENXIANGYU,wjsbg,soumikmahato,r1r13andhtt0118on Hugging Face andwssb123eon ModelScope; notable repos includeMENXIANGYU/qwen2-tinyandMENXIANGYU/qa-whl-1021. - On GPU hosts, look for the indicators Pluto published: a
/tmp/.cch/directory,/tmp/.kitsd,/etc/cron.d/.sync-helper, unexpected lines added to/root/.bashrcor/root/.profile, a process shown as[kworker/u20:1]that is actually a user process using the GPU, and Xinference model registrations namedqwen2-tiny-…orezv-…. - Check network logs for connections to 212.32.253.3 and the other IP addresses in Pluto's IOC tables. Pluto says to check any machine that loaded these repositories, even if loading failed.
- If you run vLLM, confirm you are on 0.14.0 or later: versions 0.10.1 up to 0.14.0 loaded this kind of custom code without honouring
trust_remote_code(CVE-2026-22807, GitHub advisory GHSA-2pc9-4j83-qjmr).
If you find something (in this order, per Pluto's guidance)
- Isolate the machine, restrict its outbound network access, and preserve evidence before deleting anything.
- Remove persistence: shell startup hooks, cron entries, unknown SSH keys in
authorized_keys, and malicious model registrations. The malware also deletes rival miners, so review what was removed, not only what was added. - Rotate every credential the compromised process could reach (Hugging Face tokens, cloud keys, database passwords) from a clean machine, and review their recent use.
- Rebuild from a trusted image if you cannot establish the host's integrity — especially for GPUStack hosts, given the container-to-host escape script.
Prevent
- Keep
trust_remote_codeoff by default. When a model genuinely needs it, read the Python files named in itsconfig.json, then pin that exact reviewed revision. - Require authentication on the Xinference API and limit its network reach.
- Run untrusted model code with limited privileges, restricted outbound networking and no production secrets.
The expert view
Root cause. There is no new vulnerability here; Pluto explicitly frames the mechanism as documented behaviour. trust_remote_code is a deliberate escape hatch for architectures not yet built into Transformers. The auto_map entry in config.json points at a module and class, and the loader imports that module. Any top-level code executes on import, with the privileges of the inference process — typically a GPU host with cloud credentials and broad network access. No malicious weights or pickle tricks were needed, which matters because much of the industry's model-scanning effort has focused on serialisation formats like pickle.
Why defences failed. Pluto reports that none of the 12 first-wave repositories was flagged, and the second-wave loader returned "safe" from every scanner that ran on it. Pluto's argument is that reviewing the .py files referenced by auto_map, or a simple static check at upload for risky calls such as process spawning, raw sockets or hard-coded IP addresses, would have caught every payload. Hugging Face and ModelScope removed the first-wave accounts after Pluto's report, but a second wave of 19 repositories was still live eight days after being reported, and new uploads continued after disclosure — one appeared 8.5 hours after Pluto's disclosure email. BleepingComputer reported on October 29 that Hugging Face had disabled the flagship repository but that a near-identical copy uploaded on October 25 was still serving the same miner; that copy was disabled when we checked on November 5.
Tradecraft. The payload is built for persistence and stealth: a watchdog that relaunches the miner every 120 seconds, a fileless execution path, process-name masquerading, a packed binary with altered markers to defeat standard unpacking, and status "receipts" written into Xinference's model registry so the operator can check infections remotely. The container-to-host escape aimed at GPUStack shows intent to go beyond the inference container.
Broader trend. This fits a steady run of ML-supply-chain issues in which "loading a model" quietly means "running someone's code": vLLM's CVE-2026-22807, Unsloth Studio's hard-coded trust_remote_code=True (fixed in 2026.6.9, per Pluto), two other Unsloth flaws in how it reads a model's config file, and older chat-template bugs such as CVE-2024-34359 in llama-cpp-python. AI teams often treat models as data and apply none of the dependency hygiene they use for code.
Severity in context. No CVE or CVSS score applies to the campaign itself. Direct financial damage looks small — Pluto traced 2,276 PRL, about $5,000 by its estimate, in mining proceeds to the first-wave wallet — but the access gained is the real issue: a backdoor on a GPU host with cloud credentials is a foothold, not just a power bill. The download count (one repository rose from 7,354 to 28,412 between October 20 and 28) is notable, but Pluto does not say how many were automated and does not claim confirmed infections at that scale.
Attribution. Pluto assesses, as its own judgment, a financially motivated, Chinese-speaking operator or small group, citing Simplified Chinese code comments, Alibaba Cloud infrastructure and ModelScope mirroring. One build line carries Indonesian comments, which Pluto says could mean a second operator. No government or vendor has corroborated this attribution.
Still unknown. How many hosts were actually infected; whether any were compromised via exposed Xinference APIs rather than by users loading models themselves (Pluto does not say); whether all 19 second-wave repositories are now disabled; and whether Hugging Face will add code review for auto_map modules. As of November 5, 2026, Hugging Face had not published a statement on the campaign.
Official sources
- Pluto Security — Load/Mine: Hugging Face malware campaign (October 29, 2026)
- OSV — CVE-2026-22807 / GHSA-2pc9-4j83-qjmr (vLLM auto_map code loading)
- Hugging Face repository pages, checked November 5, 2026: MENXIANGYU/qa-whl-1021, MENXIANGYU/qwen2-tiny-9, htt0118/qwen2-tiny
- Coverage: BleepingComputer — Hugging Face malware campaign returns to hijack GPUs for crypto mining (October 29, 2026)
- Coverage: Unite.AI — Pluto Security details Load/Mine cryptomining campaign on Hugging Face
- Coverage: RuntimeWire — Pluto Security traced a Hugging Face malware campaign across 31 model repositories