Load/Mine: 悪意ある Hugging Face モデルが GPU ホストをバックドア化
悪意ある Hugging Face モデルが、読み込んだ GPU ホストでマイナーとバックドアを実行しました。キャンペーンは除去のたびに戻ってきます。
要点
- Pluto Research が追跡したキャンペーンが、7 つの Hugging Face アカウントにまたがる 31 のモデルリポジトリにクリプトマイニングとバックドアのペイロードを仕込み、小さな Qwen2 テストモデルに偽装しました。カスタムコードを有効にして読み込むと、重みが一切読まれる前に発行者の Python がホスト上で実行されます。Pluto は 2026 年 10 月 29 日に分析を公開しました。
- キャンペーンと関連モデルのダウンロードは計 32,376 回、うち 29,818 回が 31 の悪意あるリポジトリでの記録です。被害は現実に進行中で、運営者のウォレットはオンチェーンで約 2,276 PRL(Pearl、約 5,000 ドル)を受け取り、稼働中のマイニングワーカーが取得時点でも報告していました。
- 標的はセルフホストの GPU 基盤、特に Xinference と GPUStack のデプロイ、借りた GPU マシン、共有研究ノートブック、小さなテストモデルを無審査で引く CI ジョブです。第二波は除去の数日後に戻り、あるリポジトリはコンテナからホストへの脱出スクリプトを運びます。
- CVE は割り当てられておらず、2026 年 11 月 3 日時点で本件は CISA の KEV カタログに載っていません。
trust_remote_codeを有効にする前にauto_mapエントリが参照する.pyファイルをすべて確認し、掲載モデルを読み込んだホストを検査してください。「インストールした場合の対処」に封じ込めの手順があります。
影響を受けますか?
以下がすべて成り立つとき影響を受けます。
- インフラの誰かが、キャンペーンのいずれかのリポジトリのモデルを、
trust_remote_code=Trueまたは対話的な確認でカスタムコードを有効にして読み込んだ。リポジトリ名とアカウント名は「侵害されたかどうかを確認するには?」に一覧があります。 - 環境がキャンペーンの標的クラスである。セルフホストの推論ホスト(特に Xinference または GPUStack)、借りた GPU マシン、共有研究ノートブック、審査なしに小さなテストモデルを引く CI ジョブ。
- ペイロードは import 時、重みが読まれる前に実行されるため、モデルの読み込みが失敗しても実行されます。基幹リポジトリの重みファイル全体が、テンソルを含まない 42 バイトの
model.safetensorsです。
第一波のアカウントは Pluto の報告後に削除されました。第二波は数日で新しいアカウントの下に現れ、報告から 8 日後もオンラインのままでした。したがって、削除通知は暴露が終わった証拠にはなりません。
| グループ | リポジトリ | 記録されたダウンロード | 2026 年 10 月 28 日時点の状態 |
|---|---|---|---|
| 第一波、hhzz667 と dsxk4mr8tq のアカウント | 12 | 728 | 削除済み |
| 第二波、MENXIANGYU と wjsbg を含む 5 アカウント | 19 | 29,090 | オンライン |
| 関連モデル、6 アカウント | 13 | 2,558 | オンライン |
キャッシュとホストを確認します。
# Any of the campaign's models in the local Transformers cache
ls ~/.cache/huggingface/hub 2>/dev/null |
grep -iE "MENXIANGYU|wjsbg|htt0118|soumikmahato|r1r13|hhzz667|dsxk4mr8tq|MONIADF-2|antwoinhjro654|vaishupv|andrew3d|oifewuheu|KzuryHD"
# Watchdog and miner artifacts on the host
ls -la /tmp/.cch 2>/dev/null
# A kernel-worker name that carries userspace arguments is the miner
ps aux | grep -F '[kworker/u20:1]'
# Persistence hooks written by the payload
grep -n "svc.py" ~/.bashrc ~/.profile /root/.bashrc 2>/dev/null
本物のカーネルワーカースレッドはコマンドライン引数を持ちません。偽装したマイナーは引数としてマイニングのログインを運び、これが Pluto の述べる識別点です。
修正方法
配信は文書化された機能を設計どおりに使ったものであり、パッケージの更新では修正されません。修正とは、auto_map エントリを持つすべてのモデルに対するレビュー規律です。
- パイプラインが
trust_remote_code=Trueで読み込むすべてのモデルを棚卸しし、そのconfig.jsonのauto_mapが参照する各 Python ファイルを次の読み込み前に通読します。Pluto が指摘するとおり、このレビューはキャンペーンの全ペイロードを検出できたはずです。 auto_mapエントリを持たず重みがsafetensorsのモデルを優先し、ジョブとノートブックではコミットハッシュでモデルのリビジョンを固定します。- Xinference と GPUStack のホストでは、モデルレジストリと API を信頼できるネットワークに制限します。ペイロードは Xinference レジストリに状態を書き込み、ある段階は GPUStack のホストディレクトリを狙うため、露出したコンソールは対象範囲です。
- 「侵害されたかどうかを確認するには?」の指標を出口でブロックし監視します。リバースシェルの受信側とプールを含みます。
Hugging Face のガイダンスはすでに作業を利用者側に置いています。フラグを有効にする前にコードを検証する。trust_remote_code=True をコピーするモデルカードやチュートリアルは、知識に基づく選択をただのチェックボックスに変え、それがまさにこのキャンペーンの狙いでした。
悪意あるコードの動作
ペイロードは小さな重みファイルの隣に置かれた普通の Python であり、import 時に実行されます。ウォッチドッグプロセス、プロキシなしのダウンローダー、カーネルワーカーに偽装したメモリ上のマイナー、リバースシェルが、モデルクラスが構築される前に組み上がります。
Transformers はカスタムモデル実装を、リポジトリの config.json の auto_map エントリが名指しするファイルを import して読み込みます。
# transformers/src/transformers/dynamic_module_utils.py (get_class_in_module)
module_spec = importlib.util.spec_from_file_location(name, location=module_file)
module = importlib.util.module_from_spec(module_spec)
sys.modules[name] = module
module_spec.loader.exec_module(module)
return getattr(module, class_name)
exec_module はクラスを定義するためにファイルのトップレベル文を実行します。定義の隣に置かれた呼び出しは getattr が返す前に走ります。28,412 回ダウンロードされた基幹リポジトリ MENXIANGYU/qwen2-tiny は auto_map を、即座に発火する入口を持つモジュールに向けています。
# modeling_evil2.py - shortened module-level entry point, published by Pluto
try:
_boot()
except Exception:
try:
_run()
except Exception:
pass
class EvilModel:
...
そこからビルドはチェーンを組み立てます。
_bootは/tmp/.cch/svc.pyを書き出します。別プロセスとして走るウォッチドッグで、120 秒ごとに欠けたマイナーを再起動します。/root/.bashrc、/root/.profile、利用者の~/.bashrcに追記された行がログインのたびに再実行します。- 3 つのビルドは
212.32.253.3:443または:9443に接続し切断のたびに再試行するリバースシェルを追加し、運営者に侵害プロセスのファイルと資格情報への対話シェルを与えます。 - マイナーバイナリ
syscore.binはモデルリポジトリまたはミラーから、ホストに設定されたプロキシを無効化して取得されます。40.6 MB の UPX 圧縮実行ファイルで、圧縮マーカーがUPX!からPEK!に変えられ、通常の展開ツールには拒否されます。 - 初回起動ではバイナリをメモリ上のファイルディスクリプターにコピーし、そこから実行しようとします。
# modeling_evil2.py - excerpt of the attempted memory-backed launch
fd = os.memfd_create("kworker")
with open(body, "rb") as f:
os.write(fd, f.read())
os.fchmod(fd, 0o755)
if os.fork() == 0:
os.setsid()
os.fexecve(fd, [_TAG] + _margs(), os.environ)
memfd_createはメモリ上に匿名ファイルを作成します。引用されたos.fexecveは CPython の標準 API ではなく、Python はos.execveでファイルディスクリプターからの実行を提供します。この抜粋は起動の試行であり、検証済みの実行トレースではありません。Pluto は watchdog の再起動用に/tmp/.cch/syncに予備のバイナリが残るとも報告しており、メモリ上の起動が成功してもディスク上に証拠が残る場合があります。[kworker/u20:1]という名前は偽装であり、ディスク上に痕跡がない証明ではありません。- 進捗報告はローカルの Xinference レジストリに
qwen2-tiny-と base32 エンコードの状態を組み合わせたモデル名として書き込まれ、API にアクセスできる運営者は各感染を読み取れます。自身のマイナーが動くと、ペイロードは競合するモデル登録を外し、一致するプロセスを kill します。
第二波の後続リポジトリ MENXIANGYU/qa-whl-1021 は、コンテナからホストへの脱出スクリプトです。特権コンテナ内から LVM ボリュームを有効化し、候補のホストディスクをマウントし、ホストのルートまたは GPUStack の /var/lib/gpustack を見つけます。そして攻撃者にホスト上の root ログインを与えます。
侵害はどのように起こりますか?
脆弱性の意味でのエクスプロイトはありません。被害者が許可を与え、発行者のコードがその下で動くだけです。
- 運営者は小さな Qwen2 テストチェックポイントに見えるリポジトリを公開します。README は公式の Qwen2.5-0.5B のモデルカードのコピーで、
config.jsonのauto_mapが悪意あるモジュールを名指しします。 - 被害者が
trust_remote_code=Trueでモデルを読み込みます。Transformers は参照ファイルをモジュールキャッシュにダウンロードして import します。 - import はモデルクラスが構築される前にモジュールのトップレベルコード
_bootを実行します。重みは読まれず、悪意ある重みも存在しません。 - 「悪意あるコードの動作」のチェーンが読み込みプロセスの権限で走り、GPU が運営者のウォレットへ採掘を始めます。
Pluto が指摘するとおり、同じ許可は他所でも失敗しています。CVE-2026-22807 では vLLM が trust_remote_code 設定を確認せずに auto_map モジュールを読み込んでおり、vLLM 0.14.0 で修正されました。Unsloth Studio はフラグをハードコードしてモデル設定を検査しており、2026.6.9 で修正されました。
攻撃の流れはどうなりますか?
カスタムコードを有効にした 1 回の読み込み呼び出しが、発行者のトップレベル Python にプロセスの権限を渡し、チェーンは重みが読まれる前に走ります。
trust_remote_code=True で呼ぶ"] --> B["config.json の auto_map が
modeling_evil2.py を指定:
import は文書化された動作"] B --> C["exec_module が import 時に
_boot を実行:コードは
クラスより先に走る"] C --> D["ウォッチドッグ /tmp/.cch/svc.py
と .bashrc フック、
マイナーを 120 秒ごとに再起動"] D --> E["syscore.bin をプロキシなしで取得、
改変された UPX マーカーで
圧縮されている"] E --> F["メモリ上の起動を試行;
予備バイナリはディスクに残る"] F --> G["マイニングプール、リバースシェル、
状態は Xinference レジストリに
隠される"]
攻撃者は何ができますか?
実証された影響は、モデルを読み込んだユーザーとしてのコード実行で、今日も動く 3 つの結果を伴います。
- 被害者の GPU でのクリプトマイニングで、オンチェーンで実現した利益があります。第一波のウォレットは 716 トランザクションで約 2,276 PRL を受け取り、約 2,241 PRL を送金済みで、取得時点の稼働ワーカーには 30 日間で約 1,008 PRL の報酬がありました。
- マイナーより長く残るバックドアアクセス。リバースシェルは切断のたびに再接続し、後段のドロッパーの一つは許可リストの IP にのみ応答し、他には
static ip.というテキストと403を返すため、同じ URL を取得した分析者はペイロードを見逃せます。 - GPU 基盤内部への横方向のリーチ。コンテナ脱出スクリプトは特権コンテナの下のホストを狙い、第二波の一つのファミリーは LLaMA-Factory デプロイの GPU プラットフォーム情報と Tencent Cloud のメタデータを収集します。
Pluto は 90 秒以内に参加した 9 台の稼働ワーカーの一群を観測しました。dhumphreys-notebook-2 や a10040gb といった名前は、マイニングファームより共有ノートブッククラスターを示します。彼らのシェア提出は約 6 分後に止まり、管理者がジョブを止めたことに一致します。運営者は計算資源を確保するため競合のマイナーとモデルも排除します。
条件は許可と、情報流出先の到達可能性です。読み込みプロセスのファイルと資格情報へのアクセスが影響範囲です。
インストールした場合の対処
まず隔離し、証拠を保存し、それから清掃します。ペイロードはモデル初期化より前に走り、そのバックドアはマイニング停止後も残り得ます。
- 対象ホストを本番ネットワークから隔離し、アウトバウンドをワークロードに必要な範囲に制限します。
- 何かを削除する前に、プロセスの詳細、ネットワーク接続、ログ、モデルキャッシュ、スタートアップファイルの変更、authorized_keys のエントリを記録します。
- 戻り経路をすべて除去します。
/tmp/.cch/ディレクトリとそのsvc.pyウォッチドッグ、ペイロードがシェルのスタートアップファイルに追記した行、自分が追加していない SSH 鍵、想定外の Xinference のモデル登録です。 - 読み込みプロセスが届け得た資格情報をすべてローテーションします。クラウドプロバイダーの鍵、レジストリのトークン、環境に保存された AI プラットフォームのトークンを含みます。
- 同じリポジトリを読み込んだ他のマシンを確認します。GPU ホストと特権コンテナでは、清掃より再構築を優先してください。脱出リポジトリはホストの root を目指し、メモリ上の起動は検査するものをほとんど残しません。
侵害されたかどうかを確認するには?
Pluto が指標を公開しています。リポジトリの状態とダウンロード数は 2026 年 10 月 28 日時点、ネットワーク基盤は 10 月 21 日が最終観測です。一致は調査すべき兆候であり、指標が 1 つ欠けても侵害は否定できません。
キャッシュとレジストリで探すリポジトリ:
- 第一波、削除済み:
hhzz667とdsxk4mr8tqが qwen2-shell、qwen2-tiny、qwen2-mini、qwen2-nano、qwen2-legacy、qwen2-final、qwen2-tiny-gpt2 を公開。 - 第二波、オンライン:qwen2-tiny と zz_ext を含む
MENXIANGYU、qwen2-final を含むwjsbg、soumikmahatoの qwen2-tiny-chat、r1r13の qwen-lora-text-v1、htt0118の qwen2-tiny。 - 関連アカウント:
MONIADF-2、antwoinhjro654、vaishupv、andrew3d、oifewuheu、KzuryHD。
ホスト上の痕跡:
/tmp/.cch/とsvc.pyプロセス、そしてkrxXJ2PKQW.workerというログインなどマイニング引数を伴う[kworker/u20:1]という名前のプロセス。svc.pyを呼び出す/root/.bashrc、/root/.profile、~/.bashrcの行。自分が追加していないauthorized_keys内の ed25519 鍵。自己テストマーカー/tmp/.qa_pwned。qwen2-tiny-またはezv-で始まる Xinference の登録。状態を base32 でエンコードします。
ブロックし追跡すべきネットワーク指標:
212.32.253.3の 443、9443、8895、8898 ポートのリバースシェル受信側とペイロード配布。送信元 IP で絞られた:8898/lf_py.pyを含みます。38.55.133.49の 8901 と 9001、第一波の Alibaba Cloud C28.137.187.63、103.97.176.121:3361、178.33.123.26の 3361 と 3362、そしてhz2006.aihzcc.top。- プール:
stratum+ssl://prl-us.kryptex.network:8048とprl-sg.kryptex.network:8048、pearl-hk.luckypool.ioの 3361 と 3956、pool.hashvault.proの 80 と 443、gulf.moneroocean.stream:10001、mine.c3pool.com:80。 - 第一波の支払いウォレット
prl1p9s2a9gdy4n5yfuf5suhya2d2pyvaahmz3n3gzm3npyxkj79m7yyq9kgnrvと第 2 ウォレットprl1pek8rh8yjck5q7596aph7ua7xnkqs8ur9mkfmz8w7xfzcdfcfx5vsx2f4lz。
タイムライン
- 2026-04-29: hhzz667 アカウントが作成され、5 か月間休眠します。
- 2026-09-21: 最初のペイロード qwen2-shell、ed25519 鍵とビーコンを備えた 37 行の SSH バックドアが公開されます。
- 2026-09-21 から 2026-09-22: 6 つのパスにまたがる鍵注入ビルドが現れ、次に完全なファイルレスマイナー qwen2-final が現れます。
- 2026-10-12: dsxk4mr8tq アカウントが 2 時間 30 分で 6 つのリポジトリを公開し、Pluto のスキャナーが
modeling_evil.pyを検出します。 - 2026-10-20: Pluto が第一波を Hugging Face と ModelScope に報告し、両社がアカウントを削除します。開示後数時間で qwen2-tiny のダウンロードは 7,354 から 9,584 へ増え、コンテナ脱出リポジトリは開示メールの 8 時間 30 分後に現れます。
- 2026-10-25: htt0118 アカウントが、以前のペイロードのほぼ同一コピーを、同じプールログインとリバースシェル受信側とともに出現させます。
- 2026-10-28: Pluto が指標スナップショットを記録します。qwen2-tiny は 28,412 回ダウンロード、第二波のリポジトリはオンラインのまま。
- 2026-10-29: Pluto が調査を公開します。
よくある質問
trust_remote_code=True は Transformers の脆弱性ですか?
いいえ。カスタム実装を必要とするモデルのための文書化された動作で、Transformers のセキュリティポリシーはこの引数を使う際にモデリングファイルの内容を常に検証するよう求めています。事故は選択を迂回するローダー側で起きています。0.14.0 より前の vLLM は設定を確認せずに auto_map モジュールを import し、Unsloth Studio はそれをハードコードしていました。
プラットフォームのスキャナーはなぜペイロードを見逃したのですか?
2 GB 未満の全ファイルが毎コミットで ClamAV を通り、パートナーのスキャナーは pickle とモデルのエクスプロイトに向けた重み形式を検査します。auto_map が参照する単純な Python ファイルは、既知のマルウェア署名でも直列化されたモデルでもありません。基幹ペイロードはスキャンを素通りし、あるスキャナーは機械学習モデルではないと報告しました。
悪意あるリポジトリはまだオンラインですか?
第一波は削除されました。19 リポジトリ 5 アカウントの第二波は、Pluto が報告してから 8 日後もオンラインで、キャンペーンは削除された第一波を数日で置き換えたため、削除は活動を終わらせていません。関連ファミリーの 1 アカウントも開示後に新しいリポジトリを公開しました。
運営者はどれほど稼いでいますか?
約 2,276 PRL(約 5,000 ドル)が 716 トランザクションで第一波のウォレットにオンチェーンで到達し、約 2,241 PRL が送金済みです。Kryptex のワーカーは取得時点で 30 日間約 1,008 PRL の報酬を示していました。関連ファミリーの MoneroOcean ウォレットは 1 か月で約 26 ドルで、この系統は金額より活動自体が意味を持ちます。
キャンペーンの背後に誰がいますか?
Pluto は、金銭動機の中国語話者の運営者か小グループと評価しています。根拠は、簡体字中国語のコメント、Alibaba Cloud の C2、ModelScope と hf-mirror.com のミラー、Xinference と Tencent Cloud を前提とする狙い、そして中国時間で深夜にあたる活動時間です。インドネシア語の parasit ツールキットは、同じ領域の第 2 の運営者の可能性があります。
safetensors の重みはこのクラスから守りますか?
いいえ。基幹リポジトリの safetensors ファイルはテンソルを持たない 42 バイトで、悪意ある重みは不要でした。ペイロードはその隣の Python です。重みの形式はコードを検読できないため、auto_map の参照には読み手が必要です。
Ostorlab で露出した AI 推論コンソールを見つける
Ostorlab の攻撃面探索は、指定範囲のインターネット公開ホストを棚卸しし、このキャンペーンが標的とする露出した Xinference または GPUStack のコンソールをすべて見つけます。Ostorlab でスキャンを始めると、どの推論ホストからネットワーク制限をかけるべきかがわかります。
参考資料
- Pluto Security、「Load/Mine: A Hugging Face Malware Campaign Returns After Takedown」、2026 年 10 月 29 日公開(Shaked Chen、Eitan Chassid、Yotam Perkal)、ペイロード分析、アカウント追跡、完全な指標一覧を含む: https://pluto.security/blog/hugging-face-malware-campaign-load-mine (2026 年 11 月 3 日確認)
- Transformers のソース、
dynamic_module_utils.py。キャンペーンが悪用するget_class_in_moduleの import 経路: https://github.com/huggingface/transformers/blob/main/src/transformers/dynamic_module_utils.py (2026 年 11 月 3 日確認) - Transformers のセキュリティポリシー、「please always verify the content of the modeling files when using this argument」とリビジョン固定の推奨: https://github.com/huggingface/transformers/blob/main/SECURITY.md (2026 年 11 月 3 日確認)
- Hugging Face Hub のセキュリティ文書、マルウェアと pickle のスキャン機能とその限界: https://huggingface.co/docs/hub/security (2026 年 11 月 3 日確認)
- Xinference の README、レジストリ確認に使う標準的なデプロイポート: https://github.com/xorbitsai/inference (2026 年 11 月 3 日確認)
- CISA の Known Exploited Vulnerabilities カタログ JSON フィード、本キャンペーンの CVE エントリが 2026 年 11 月 3 日時点で存在しないことを確認: https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (2026 年 11 月 3 日確認)
- Python os ドキュメント、
os.execveのファイルディスクリプター対応:https://docs.python.org/3/library/os.html#os.execve (2026 年 11 月 3 日確認)