Threat

Hugging Face Malware and trust_remote_code

Page published · Page updated

Dossier

Earliest dated coverage: 30 Oct 2026 · First observed: 12 Nov 2026 · Latest dated coverage: 30 Oct 2026

Coverage timeline

30 Oct 2026brandefense.io

Single-source incident — one report is available.

Why it matters

Malicious Hugging Face repositories can execute Python with the model loader's privileges before model initialization, making repository code review and execution isolation essential when enabling trust_remote_code.

A Hugging Face malware campaign reported by Pluto Security distributed 31 malicious model repositories across seven accounts, abusing Transformers' trust_remote_code=True option to execute cryptocurrency-mining payloads. The campaign and linked models recorded more than 32,000 downloads, which do not represent confirmed infections, although Pluto reported mining activity and wallet payments. The attack exploits an explicit code-execution opt-in rather than a Transformers vulnerability.

campaign

Summary

Brandefense's account of Pluto Security's research describes a cryptocurrency-mining campaign distributed through 31 malicious Hugging Face model repositories across seven accounts. The repositories appeared in two waves beginning in September 2026. Reported downloads comprised 728 for the first wave and 29,090 for the second wave by 28 October; another 2,558 downloads belonged to 13 linked models sharing techniques but without proven common ownership. These figures measure downloads, not unique victims or successful infections.[0]

The campaign exploited a trust decision rather than a demonstrated flaw in the core loading mechanism. With trust_remote_code=True, Transformers imports repository Python referenced by config.json auto_map entries, allowing top-level payload statements to run with the caller's privileges before the model exists. The flagship repository reportedly carried an empty, 42-byte model.safetensors file: execution depended on adjacent Python, not malicious tensor contents. Consequently, an unsuccessful model load or the presence of safetensors weights did not establish that a machine was safe.[0]

The reported payload targeted GPU-capable environments, especially self-hosted Xinference and GPUStack deployments. The main second-wave build combined a persistent watchdog, a memory-launched miner disguised as [kworker/u20:1], and local status reporting through fake Xinference registrations. Three builds also opened reverse shells, while a later script attempted privileged-container escape and host-root access. Pluto's reported wallet receipts of approximately 2,276 PRL, valued at roughly US$5,000, and observations of live mining workers support actual compromise, but do not establish the total victim population.[0]

Takedowns reduced availability without fully eliminating the reported distribution. Brandefense's 30 October check found 18 of 19 second-wave repositories disabled, while one copy uploaded on 25 October remained reachable. The article also reports that first-wave repositories and the flagship Python payload escaped the scanners described in the investigation. The intelligence rests on one supplied article: its account of Pluto's findings, its own API observations, and its summaries of linked documentation are not independently corroborated by additional supplied source bodies. No named actor is established.[0]

Attack chain

  1. Publish malicious model repositories: The operator distributed repositories posing as usable models across seven Hugging Face accounts. One prominent repository presented itself as a tiny Qwen2 test checkpoint. The article describes two publication waves and renewed distribution within days of the first takedown.[0]
  2. Trigger repository-supplied Python during loading: A load using trust_remote_code=True caused Transformers to retrieve and import Python named by config.json auto_map. Top-level statements executed before model creation, placing execution before any subsequent model-load failure.[0]
  3. Deploy mining and supporting components: The main second-wave build installed a watchdog under /tmp/.cch/, launched a miner using memfd_create with the process name [kworker/u20:1], and wrote status reports into the local Xinference registry as fake model names. A fallback miner copy remained on disk despite the memory-launch technique.[0]
  4. Resume through shell-startup persistence: Hooks in shell startup files allowed the watchdog to return at a subsequent login. The article explicitly warns that terminating the miner alone does not remove persistence.[0]

Disclosure timeline

DateEvent
2026-09The article places the beginning of repository publication in September 2026 and describes two waves; it does not supply an exact campaign start day.[0]
2026-10-25A copy later found reachable during Brandefense's 30 October check was uploaded by a newer account.[0]
2026-10-28The download-count snapshot cited from Pluto recorded 29,090 second-wave downloads and 2,558 downloads for additional linked models. The dominant second-wave repository had reached 28,412 downloads.[0]
2026-10-29Brandefense identifies this as the publication date of Pluto Security's campaign report.[0]
2026-10-30T10:14:00ZBrandefense queried the public Hugging Face model API for the 19 second-wave repositories. It found 18 disabled and one reachable copy with 85 downloads; the flagship was disabled and had an API download count of 29,095. The check inspected metadata and file listings without downloading or executing model files.[0]
2026-10-30Brandefense published its campaign explainer, incorporating Pluto's reported findings and its own takedown-status checks.[0]

How it works

The central mechanism is an explicit remote-code loading capability. A repository's config.json can identify custom implementation files through auto_map. When trust_remote_code=True is used, Transformers downloads and imports that Python. Python executes a module's top-level statements during import, so a malicious call can run before model instantiation and with the loading process's privileges. The article explicitly characterizes this as documented behavior rather than a vulnerability in Hugging Face.[0]

The malicious code path was separate from weight deserialization. Pluto reportedly found no tensors in the flagship's 42-byte model.safetensors file, while its payload resided in a neighboring Python file. Safetensors can avoid pickle-based execution from weight files, but does not prevent execution of Python separately authorized through trust_remote_code.[0]

The main second-wave payload used memfd_create to launch the miner from memory and adopted [kworker/u20:1] as a kernel-thread-like disguise. This was not an entirely diskless deployment: the article also describes an on-disk fallback and a watchdog directory under /tmp/.cch/. Local Xinference registrations carried status reports disguised as model names.[0]

Capabilities varied between builds. Three reportedly opened reverse shells. A later script, published 8.5 hours after Pluto's disclosure email, attempted to escape a privileged container and gain root on the host, and searched for GPUStack's data folder. The article does not establish that the escape succeeded or that every repository carried these additional capabilities.[0]

The reported scanning failure concerned malicious Python selected by the model configuration. According to the article, none of the first-wave repositories was flagged, the flagship Python file received clean results from all scanners that ran, and JFrog's tool classified it as not being a machine-learning model. The article distinguishes this code-import path from scanners focused on known malware signatures or model-weight formats.[0]

Separate serving-stack weaknesses could undermine intended loading controls. The article describes forced remote-code trust in older Xinference loaders, incomplete revision propagation in certain vLLM loads, a vLLM path that failed to check the trust flag, and a Transformers crafted-configuration execution issue. These are related hardening concerns; the supplied evidence does not demonstrate that the campaign exploited those specific CVEs.[0]

Affected versions and patch status

ProductAffectedPatch status
Xinference — related remote-code trust control issueBefore 2.12.0, the article reports that six loaders passed trust_remote_code=True without a setting to disable it; associated identifier: CVE-2026-76841.The article identifies 2.12.0 as the version boundary for the described behavior. It does not establish exploitation of this CVE by the campaign.[0]
vLLM — related revision-pinning issueThe article describes vLLM 0.22.1 before 0.28.0 as failing to propagate a revision pin to some tokenizer and configuration loads for two model types; associated identifier: CVE-2026-100653.The article identifies 0.28.0 as the end of the described affected range. It does not establish exploitation of this CVE by the campaign.[0]
Hugging Face Transformers — related crafted-configuration execution issueBefore 5.3.0, the article reports that a crafted config.json could cause code retrieval and execution through a standard from_pretrained call; associated identifier: CVE-2026-4372.The article identifies 5.3.0 as the version boundary for this separate issue. It does not describe a campaign-specific patch for the documented trust_remote_code behavior or establish exploitation of this CVE.[0]

Indicators of Compromise

TypeIndicatorContext
file-path/tmp/.cch/Reported watchdog directory in the main second-wave payload. Investigate its contents alongside model-loading history and persistence changes.[0]
othersvc.pyThe article recommends hunting unexpected processes using this script name. A name match requires contextual validation rather than being treated as conclusive compromise.[0]
other[kworker/u20:1]Reported disguise used by the memory-launched miner. The article recommends checking for this process name with mining arguments.[0]
file-pathsyscore.binMiner filename attributed to Pluto's findings; Brandefense observed it in the file listing of the copy still reachable on 30 October. No full filesystem path is supplied.[0]
otherqwen2-tiny-Prefix the article recommends investigating in anomalous local Xinference model registrations, which the payload used for status reporting.[0]
otherezv-Additional prefix the article recommends investigating in anomalous local Xinference model registrations. This is a contextual hunting lead, not a complete malicious registration name.[0]

Key takeaways

  • Treat trust_remote_code as authorization to execute a software dependency, not as a routine model-loading checkbox. Review and pin the Python selected by auto_map; weight-format safety does not cover that code.[0]
  • Exposure and impact must remain separate: more than 32,000 reported downloads included additional models with unproven common ownership and did not establish an equivalent victim count. Wallet receipts and observed workers support actual mining compromise, but not its full scale.[0]
  • Neither clean scan results nor broad repository takedowns established eradication. The article reports missed malicious repositories and a reachable copy after most second-wave repositories had been disabled.[0]
  • No named actor is supported. Brandefense relays an assessment of a financially motivated, Chinese-speaking operator, but the language, hosting, and activity-hour observations do not by themselves establish a named organization or nationality.[0]
  • All substantive findings in this dossier are single-source at the supplied-evidence level. The original research and vendor advisories are linked or summarized by the article, but their bodies were not supplied for independent corroboration.[0]

Defensive actions

  • Review every Python file referenced by config.json auto_map before permitting remote-code loading.: The payload executed through imported Python rather than model weights. The article specifically recommends examining uses of subprocess, socket, and ctypes, and relays Pluto's assessment that this review would have caught every payload in the campaign.[0]
  • Pin model loading to the exact reviewed commit using revision=, and verify that the serving stack propagates that pin.: Revision pinning prevents a later repository push from silently replacing reviewed code. The article describes a related vLLM issue in which some tokenizer and configuration loads did not receive the pin.[0]
  • Check remote-code controls in Xinference and vLLM, using the version boundaries reported in the article to identify deployments needing remediation.: The article reports forced trust_remote_code=True in Xinference before 2.12.0, incomplete revision propagation in the described vLLM range before 0.28.0, and a separate vLLM flag-check bypass. Application-level policy is insufficient if the serving stack bypasses or fails to propagate it.[0]
  • Load newly acquired models in an environment with limited privileges, restricted outbound networking, and no production secrets.: Repository code runs with the loader's privileges. Reported variants included reverse shells and an attempted privileged-container escape, extending the risk beyond unauthorized GPU consumption.[0]
  • Retain safetensors as a weight-format control, but do not treat it as approval for repository-supplied Python.: The flagship used an empty safetensors file while executing its payload from adjacent Python. Safetensors did not protect the separate trust_remote_code import path.[0]
  • Investigate machines that loaded a suspect repository even if model initialization failed or GPU use appears normal.: Top-level Python payload statements run before model creation. Hunt for /tmp/.cch/, unexpected svc.py processes, mining arguments associated with [kworker/u20:1], and anomalous qwen2-tiny- or ezv- Xinference registrations.[0]
  • Monitor GPU utilization and cloud billing for unexplained increases associated with model-loading environments.: The campaign monetized access through GPU mining, and the article identifies elevated GPU activity or bills as possible early signs.[0]
  • Isolate suspected hosts and preserve process lists, connections, logs, and the model cache before deleting artifacts.: These are the evidence-preservation steps recommended in the article and retain information about the running payload and the model code that introduced it.[0]
  • Review shell startup files, cron jobs, and SSH authorized_keys rather than stopping at miner termination.: The reported watchdog used shell-startup hooks, and the article identifies these locations as persistence checks. Killing the miner alone does not establish removal.[0]
  • From a clean machine, rotate tokens, cloud credentials, and SSH keys accessible to the compromised process; rebuild from a trusted image if host cleanliness cannot be established.: The imported payload ran with the caller's privileges, and some builds provided remote access. The article specifically recommends credential rotation and a trusted rebuild when cleanup cannot be proven.[0]