2026年5月19日 01:56 UTC、中国のAlibaba傘下Ant Designチームが管理するデータ可視化ライブラリ群 @antv のnpmメンテナアカウント atool が乗っ取られ、323パッケージ・639バージョンにMini Shai-Huludマルウェアが混入した。攻撃者はわずか22分間の自動化バーストで大量の悪性バージョンを公開し、週約110万ダウンロードを誇る echarts-for-react を含む多数の広く使われるパッケージを汚染した。
悪性ペイロードはインストール時に自動実行され、AWS・GitHub・Kubernetes・Vault・SSH等20種類以上の認証情報を収集してC2サーバーへ暗号化送信する。
npmサプライチェーン攻撃全体の防御フレームワークと恒久対策についてはサプライチェーン攻撃とは|手口・防御ツール比較・npm 12の新機構まで実践解説をご覧ください。
- ・2026-05-19 01:56〜02:56 UTCの22分間に323パッケージ・639悪性バージョンが一斉公開された。
- ・侵入口はメンテナアカウント
atoolの乗っ取りで、@antv/g2・g6・x6・echarts-for-react等を汚染。 - ・preinstallフックでBunを経由して実行され、AWS/GitHub/K8s/Vaultなど20種類以上の認証情報を盗む。
- ・npm tokenを窃取してワーム化し、被害者の管理パッケージにも自動混入して拡散を続ける。
- ・Socketの中央値検知時間は6.7分、2200以上のGitHubリポジトリが既に窃取トークンで作成された。
本記事が扱う5月19日の波と同一のC2インフラを使う攻撃が、2026-09-07にまったく別の4パッケージ(
feishu-docx-mcp / blueai-cli / bmc-i18n-extract-cli / bmc-translate-utils)で観測された。4版とも1.206秒のバーストで公開され、約4時間25分後にnpmセキュリティチームが差し押さえ済みだ。@antvエコシステムは今回の対象ではない。レジストリ実測にもとづく詳細と、対照群で検証した確認コマンドは「10. 2026年9月7日——同じペイロードが111日ぶりに再浮上した」にまとめた。1. 何が起きたか――22分間の自動化汚染バースト
時刻はすべてUTC。Socket Threat Research Teamの分析および各セキュリティベンダーの報告をもとに整理する。
| 日時 (UTC) | 出来事 |
|---|---|
| 2026-05-19 01:56 | 最初の悪性バージョンがnpm Registryに公開される |
| 2026-05-19 01:56〜02:56 | 22分間の自動化バーストで323パッケージ・639バージョンを連続公開 |
| 2026-05-19 02:02 | Socketが最初の悪性パッケージを検知(公開から約6分後) |
| 2026-05-19 02:02〜03:09 | Socketが639バージョン中の大半を順次検知(中央値6.7分) |
| 2026-05-19 午前(JST) | StepSecurity・OX Security・Wiz Researchが個別分析レポートを公開 |
| 2026-05-19 | Microsoft Security Intelligenceが公式アラートを発出 |
今回の攻撃が従来のサプライチェーン攻撃と一線を画す点は「22分間の自動化バースト」にある。TanStack事件では6分間隔で2回のダブルタップパターンが観察されたが、@antv事件では1時間かけてほぼ全メンテナパッケージを網羅する自動化スクリプトが稼働した。639バージョンを1時間以内に公開するには人力ではまず不可能であり、攻撃者は事前に自動化ツールをセットアップしてatoolアカウントの乗っ取りを待っていたと考えられる。
攻撃を検知したSocketは、検知した339バージョンについて中央値6.7分という速さでアラートを発行した。しかし残念ながら、この6.7分の検知時間でも npm install を即座に走らせる多くのCI/CDパイプラインは感染した状態でビルドを完了させてしまった。
2. @antvとは何か――Ant Designを支えるデータ可視化エコシステム
@antv はAlibaba傘下のAnt Groupが開発・維持する大規模なデータ可視化ライブラリ群で、中国最大のエンタープライズUIシステム「Ant Design」と密接に統合されている。世界中の金融・BI・ダッシュボード系アプリケーションで使われており、そのダウンロード数は合計で週5000万を超える。
主要パッケージのスコープは以下の通りだ。
| パッケージ | 用途 | 週次DL規模 |
|---|---|---|
@antv/g2 |
文法ベースのグラフ描画(Grammar of Graphics) | 数十万 |
@antv/g6 |
グラフ(ネットワーク図)可視化 | 数十万 |
@antv/x6 |
フロー図・ダイアグラム | 数十万 |
@antv/l7 |
地理空間可視化(地図レイヤー) | 数万 |
@antv/s2 |
多次元表分析 | 数万 |
@antv/f2 |
モバイル向けグラフ | 数万 |
@antv/g2plot |
チャートライブラリ | 数十万 |
@antv/graphin |
React向けグラフ可視化 | 数万 |
echarts-for-react |
Apache EChartsのReactラッパー | 約110万 |
timeago.js |
相対時刻表示ユーティリティ | 約150万 |
特筆すべきは echarts-for-react(週約110万DL)と timeago.js(週約150万DL)だ。どちらも atool アカウントが共同メンテナとして参加しており、@antv名前空間外のパッケージにも攻撃が波及した。今回の攻撃対象323パッケージのうち、@antv名前空間は直接的な標的であったが、@lint-md・@openclaw-cn・@starmind 等の関連名前空間パッケージも含まれている。
このエコシステムの規模が今回の攻撃を特に深刻なものにしている。@antv/g2やecharts-for-reactはReactエコシステムにおいて定番のグラフライブラリであり、「自分はTanStackを使っていないから安全だ」と判断していた多くのフロントエンド開発者・データエンジニアリングチームが今回の標的に含まれることになった。
3. 侵入経路と攻撃フロー――atoolアカウント乗っ取りからワーム化まで
攻撃の起点はnpmメンテナアカウント atool(メールアドレス: atool@alibaba-inc.com)の乗っ取りだ。Socket・StepSecurityの分析によると、攻撃者はこのアカウントの認証情報を何らかの手段(クレデンシャルスタッフィング、フィッシング、または以前のデータ漏洩)で入手し、atoolが管理する全パッケージに一気にアクセス権を得た。
攻撃フロー全体を以下の図で示す。
2026-05-19 01:56 UTC"] -->|"22分間 自動投稿"| B["npm Registry
639悪性バージョン 323パッケージ"] B -->|"npm install 実行"| C["開発者PC または CI/CD環境"] C -->|"preinstall hook 起動"| D["悪性 index.js 実行
1728エントリ難読化テーブル"] D --> E["認証情報 20種以上収集
AWS / GitHub / K8s / SSH / Vault 等"] D -->|"npm token 窃取"| F["伝播ロジック起動
被害者管理パッケージに混入"] E -->|"AES-256-GCM 暗号化送信"| G["C2サーバー
t.m-kosche.com:443"] E -->|"GitHubトークン流用"| H["GitHubリポジトリ
デッドドロップ作成"] F -->|"ワーム化 再公開"| B
Step 1 — アカウント乗っ取りと自動投稿
攻撃者はatoolアカウントの認証情報を使って npm Registry の API に直接アクセスし、自動化スクリプトで323パッケージの tarball を取得した後、各パッケージに悪性ペイロードを注入してバージョン番号を上げてから再公開した。この一連の作業が22分間で完了した。
Step 2 — preinstallフックによる実行
各悪性パッケージの package.json には "preinstall": "bun run index.js" というスクリプトフックが追加されている。npm install を実行した開発者・CIシステムはパッケージのインストール前にこのフックが自動的に発火する。Bunがインストールされていない環境ではペイロードが curl を使ってBunを自動インストールしてから実行する。
Step 3 — 難読化と認証情報収集
悪性の index.js は非常に高度に難読化されており、1728エントリの文字列配列ルックアップテーブルとPBKDF2シードのFisher-Yatesシャッフル・カスタム文字列暗号復号器を組み合わせている。静的解析ツールでは一見無害なコードに見える。実行時に復号されて130以上の認証情報ファイルパターンを順次スキャンし、見つかった認証情報を収集する。
Step 4 — 二重チャンネル流出
収集した認証情報はgzip圧縮後にAES-256-GCMで暗号化し、RSA-OAEPでAESキーをラップしてC2サーバー(t.m-kosche.com:443)に送信する。フォールバックとして、窃取したGitHubトークンを使って被害者アカウントに公開リポジトリを作成し、results/results-<timestamp>-<counter>.json に窃取データをコミットするデッドドロップ手法も用いる。
作成されたリポジトリの説明文は niagA oG eW ereH :duluH-iahS(逆から読むと “Shai-Hulud: Here We Go Again”)という特徴的な文字列だ。
Step 5 — npm伝播(ワーム化)
攻撃の最も危険な側面がこのワーム化機能だ。ペイロードは窃取したnpmトークンを使ってnpm Registry APIでトークンを検証し、そのトークン所有者が管理する全パッケージを列挙する。次にそれらのパッケージのtarballをダウンロードして同一の悪性ペイロードを注入し、バージョン番号をインクリメントして再公開する。
これにより攻撃の初期標的(@antv)を超えて、被害者自身の管理パッケージも感染源になってしまう。この機能によってSocket追跡では総計2200以上のGitHubリポジトリが既に窃取されたトークンで作成されていることが確認された。
4. ペイロードの破壊力――20種類以上の認証情報を根こそぎ盗む
悪性ペイロードが収集する認証情報は130以上のファイルパターンを対象としており、現代のクラウドネイティブ開発者が使うほぼすべての重要クレデンシャルを網羅している。
- ・AWS: 環境変数(AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)、~/.aws/credentials、EC2インスタンスメタデータ(IMDS v1/v2)、ECSコンテナメタデータ、Secrets Manager。
- ・GitHub: ~/.config/gh/hosts.yml、GitHub Personal Access Token、GitHub Actions ランナーメモリからのシークレット直接読み取り。
- ・Kubernetes: サービスアカウントトークン(/var/run/secrets/kubernetes.io/serviceaccount/token)、kubeconfig(~/.kube/config)。
- ・HashiCorp Vault: VaultトークンおよびVaultシークレット。
- ・SSH: ~/.ssh/ 配下の秘密鍵全般。
- ・Docker: ~/.docker/config.json(レジストリ認証情報)、Dockerソケット経由のコンテナエスケープ試行。
- ・その他: npm auth token、GitLab CI/CD変数、Azure DevOps PAT、Stripe APIキー、データベース接続文字列、暗号通貨ウォレット。
GitHub Actionsランナーメモリの読み取りはこの攻撃の特に注目すべき能力だ。StepSecurityの分析によると、ペイロードは /proc/[pid]/cmdline をスキャンして Runner.Worker プロセスを特定し、/proc/[pid]/mem 経由でプロセスメモリを直接読み取る。
これによりGitHub Actionsがログにマスクして表示している *** 形式のシークレットでさえ、実際の値が流出する。この手法はGitHub Actionsの機密情報保護機能を完全に回避する。
対象とするCI/CDプラットフォームは10以上に上る。GitHub Actions・GitLab CI・Travis CI・CircleCI・Jenkins・Azure DevOps・AWS CodeBuildなど、現代の開発組織が使うほぼすべてのCI/CDシステムが標的だ。
收集した認証情報はAES-256-GCMで暗号化しRSA-OAEPでAESキーをラップした後、OpenTelemetryのAPIパスを模した https://t.m-kosche.com:443/api/public/otel/v1/traces に送信される。このエンドポイントのパスが正規の可観測性エンドポイントに偽装されているのは、ネットワーク監視ツールのシグネチャをかいくぐるためと考えられる。
5. 自分の環境が感染しているか確認する5ステップ
Step 1 — ロックファイルのスキャン
# package-lock.json / pnpm-lock.yaml / yarn.lock で対象パッケージを確認
grep -E '"@antv/|echarts-for-react|timeago\.js|size-sensor|canvas-nest' \
package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null
バージョン番号が確認できたら、Socketの公開IOCリスト(socket.dev/blog/antv-packages-compromised)と照合して悪性バージョンかどうかを確認する。原則として2026-05-19 01:56〜02:56 UTCの間に公開されたバージョンは疑うべきだ。
Step 2 — preinstallフックの検索
# node_modules内で悪性のpreinstallフックを持つpackage.jsonを検索
find node_modules -name "package.json" -not -path "*/node_modules/*/node_modules/*" \
-exec grep -l '"preinstall".*"bun run index.js"' {} \;
# 大きな難読化index.jsを検索(400KB超はほぼ確実に悪性)
find node_modules -name "index.js" -size +400k -type f | head -20
Step 3 — GitHubデッドドロップリポジトリの確認
# GitHubに見覚えのない公開リポジトリが作られていないか確認
# GitHub CLIを使う場合
gh repo list --visibility public --json name,description | \
grep -i "niagA\|Shai-Hulud\|sayyadina\|stillsuit"
# または gh api を直接叩く
gh api user/repos --paginate -q '.[] | select(.private == false) | [.name, .description] | @tsv' | \
grep -i "shai"
Step 4 — ネットワーク接続ログの確認
CIログまたはホストのネットワークログで以下のドメインへの接続を確認する。
t.m-kosche.com(C2サーバー、ポート443)- 2026-05-19 01:56〜03:00 UTC の時間帯に実施したビルド・npm installと相関があるか
Step 5 — 永続化マーカーの確認
# 悪性ペイロードが置く永続化ファイルを確認
ls -la .claude/setup.mjs .vscode/setup.mjs 2>/dev/null
cat ~/.local/bin/gh-token-monitor.sh 2>/dev/null
# systemdユーザーサービスの確認(Linux)
systemctl --user list-units | grep monitor
# LaunchAgentの確認(macOS)
ls ~/Library/LaunchAgents/ | grep monitor
いずれかが発見された場合は後述の緊急対処手順を直ちに実施する。
6. 緊急対処手順――正しい順序で実施する
- ・ネットワーク遮断より先にシークレットローテーションを行う。ランナー監視スクリプト等のkill switchがある場合、先に切断すると関係ないデータ破壊を引き起こす可能性がある。
- ・ローテーション→node_modules削除→クリーンインストールの順で実施する。
① 即座にCI/CDシークレットをローテーション
GitHub ActionsのシークレットをGitHub管理画面から更新する。AWS IAMアクセスキーを無効化して新しいキーを発行する。npm publish tokenを失効させて新しいトークンを生成する。Vault tokenをrevokeする。SSH鍵の場合は旧鍵を ~/.ssh/authorized_keys から削除してから新しい鍵ペアを生成する。
② 影響を受けたパッケージのダウングレード
package.json で影響を受けたバージョンを2026-05-19より前のクリーンバージョンに固定する。その後 npm install を実施するが、--ignore-scripts フラグを付けて実行する。
③ node_modulesの完全削除と再インストール
rm -rf node_modules package-lock.json
npm install --ignore-scripts
この際、.npmrc に ignore-scripts=true を追加しておくことで、次回以降のinstall時もpostinstallフックが実行されないようにする。
④ 永続化マーカーの削除
Step 5で見つかった永続化ファイルを削除する。systemdユーザーサービスは systemctl --user disable --now <service名> で無効化する。LaunchAgentは launchctl unload ~/Library/LaunchAgents/<plist名> で停止してからファイルを削除する。
⑤ GitHubの見覚えのない公開リポジトリを削除
デッドドロップとして作成されたリポジトリには実際の窃取データが含まれているため、速やかに削除する。ただし削除前にリポジトリの内容をダウンロードして、どの認証情報が流出したかを記録・確認しておくことを推奨する。
7. TanStack事件との比較――同一ワームの進化と拡大
Mini Shai-Huludワームは2026年5月11日のTanStack事件以来、わずか8日間でさらに大規模な攻撃へと進化した。以下の比較表で両事件の主要な違いを整理する。
| 比較項目 | TanStack事件(2026-05-11) | @antv事件(2026-05-19) |
|---|---|---|
| 侵入手法 | GitHub Actions OIDC トラステッドパブリッシャー悪用 | メンテナアカウント(atool)直接乗っ取り |
| 汚染パッケージ数 | 14パッケージ | 323パッケージ(約23倍) |
| 悪性バージョン数 | 28バージョン(2回×14) | 639バージョン |
| 攻撃実施時間 | 6分間(ダブルタップ×2回) | 22分間(自動化バースト) |
| 最大DL規模 | @tanstack/react-router(数百万/週) | echarts-for-react(約110万/週)+timeago.js(約150万/週) |
| 実行トリガー | preinstall + optionalDependencies | preinstall + Bun自動インストール |
| デッドマンズスイッチ | rm -rf ~/ あり | 確認なし |
| C2エンドポイント | 同系統 | t.m-kosche.com:443 |
| GitHubデッドドロップ | あり | あり(2200以上のリポジトリ作成) |
| BreachForumsソース公開 | なし | あり(攻撃コンテスト形式) |
| 帰属 | TeamPCP | TeamPCP(中程度の確信度、Wiz Research) |
| Socket検知中央値 | 数時間後 | 6.7分 |
最も重要な変化の一つは「BreachForumsでのソースコード公開」だ。Wiz Researchの分析によると、TeamPCPは@antv攻撃の前後にMini Shai-Huludのソースコード全体をBreachForumsで公開し、サプライチェーン攻撃コンテストを告知した。これは攻撃の「民主化」を意味し、今後は技術力の低い攻撃者でも同一手法でnpmサプライチェーン攻撃が実施できるようになる可能性を示している。
TanStack事件との比較詳細についてはTanStack公式@tanstack/*にマルウェア混入|205パッケージに広がるMini Shai-Huludワームを参照してほしい。
また、npm名前空間を悪用したブランドスクワット型の攻撃パターンについては偽TanStackパッケージが.env窃取|npmブランドスクワット攻撃の全容と緊急対策も参考になる。
8. 組織として今すぐやること――再発防止の恒久対策
- ・今日中: CI/CDシークレットのローテーション、lock ファイルの確認、ignore-scripts設定の有効化。
- ・今週中: Socket / Aikido / Snyk をCI/CDに組み込む、npm audit signaturesを自動化、dependencyレビューワークフローを追加。
- ・今月中: npm 2FAの全メンテナへの強制、trusted publisherへの移行、社内レジストリプロキシの導入検討。
1. preinstallフックのデフォルト無効化
CI/CDパイプラインの .npmrc に ignore-scripts=true を追加することがまず最初の一手だ。postinstall・preinstallフックは多くの攻撃の実行トリガーになっており、本当に必要なパッケージに対してのみ個別に許可するポリシーが望ましい。一方でネイティブモジュール(node-gyp 等)はbuildスクリプトが必要なケースも多いため、CI環境でのみこの設定を有効にするか、許可リスト方式を採用するかを組織の状況に合わせて判断する。
2. 依存関係スキャナをCIに組み込む
Socketはpackage.jsonの変更時に自動でPRコメントを追加するGitHub Appを提供している。Aikido SecurityはCI内でリアルタイムスキャンを実施する。どちらも npm install を実行する前に悪性シグナルを検出でき、今回の事件のように6〜7分で検知が可能になる。
3. npm 2FAの全メンテナへの強制
今回の攻撃の根本原因はメンテナアカウントの乗っ取りだ。npm Registry の組織設定で、パッケージの publish には 2FAを必須とするポリシーを設定する。npm本体も2023年以降、一定の基準を満たすパッケージに対してトラステッドパブリッシャー(GitHub Actions OIDC)への移行を推奨しているが、今回の事件のようにメンテナが複数いるエコシステムではすべてのメンテナのアカウントセキュリティを管理することが難しい。
4. lock ファイルのCI検証とdependency review
GitHub Actionsの dependency-review ワークフローを追加することで、PRがマージされる前に依存関係の変化を自動検知できる。またPR時にlock ファイルのdiffを必ずレビューするルールを設けることも有効だ。攻撃者は package.json への直接変更を最小化して lock ファイルレベルでの変化を狙うケースがあるため、lock ファイルのdiff確認が重要になる。
5. ネットワークレベルでのC2ドメインブロック
今回判明したC2ドメイン t.m-kosche.com をファイアウォールまたはDNSフィルタリングでブロックする。ただしこれはすでに感染した環境での流出防止であり、感染そのものの予防にはならない点に留意が必要だ。GitHubデッドドロップについては、GitHubそのものをブロックするわけにはいかないため、GitHubトークンのスコープを最小化して意図しないリポジトリ作成ができないようにする(repo スコープの代わりに読み取り専用スコープ read:user のみ付与する等)。
6. CI/CDパイプラインのランナーメモリ保護
今回のペイロードはGitHub Actionsランナーの /proc/[pid]/mem を読み取ってマスクされたシークレットを窃取する。StepSecurityのHarden-Runnerを使うと、このようなプロセスメモリ読み取りをブロックすることができる。また seccomp プロファイルでプロセス間メモリ読み取りシステムコール(ptrace・process_vm_readv等)を制限するのも効果的だ。
CI/CDパイプラインのセキュリティ強化全般についてはAI自動化ツール完全ガイド2026|導入から本番運用までのDevOpsセキュリティセクションも参考にしてほしい。
9. 攻撃者帰属――TeamPCPとBreachForumsコンテストの深刻な含意
Wiz Researchは中程度の確信度でこの攻撃活動を脅威アクター「TeamPCP」に帰属させている。帰属の根拠はインフラストラクチャの重複(C2ドメインの使い回し)、マルウェア機能の一致、オペレーション上のパターン、および過去のTanStack事件との手法的な連続性だ。
TeamPCPは金銭目的の動機を持つ脅威アクターとして追跡されており、窃取した認証情報をダークウェブマーケットで販売するか、直接的なクラウドリソースの不正使用に転換すると考えられている。AWSクレデンシャルが一つでも流出すれば、不正なEC2インスタンスを大量に起動して暗号通貨マイニングに使用するといった手法で直接的な金銭的利益を得ることができる。
特に深刻なのは「攻撃のオープンソース化」だ。Mini Shai-Huludのソースコードが公開されたことで、この攻撃パターンが一部の脅威アクターだけのものではなくなった。BreachForumsでのコンテスト告知は「最も多くのパッケージを汚染できた参加者に賞金を出す」という形式だったとWizの分析では言及されており、今後この攻撃手法を使う主体が増えることが予測される。これはnpmエコシステム全体として対処を迫られる問題だ。
10. 2026年9月7日——同じペイロードが111日ぶりに再浮上した
2026年9月7日、本記事が扱った@antv事件と同一のC2インフラを使うペイロードが、まったく別の4パッケージに載って再びnpmへ公開された。最初に報告したのはAikido SecurityのCharlie Eriksen氏で、同社は「5月19日を最後に消えていたハッシュが111日ぶりに再出現した」と表現している。以下は当サイトがnpmレジストリのpackumentを直接引いて独立に確認した内容で、観測時点は2026-09-08 06:20 JSTだ。
timeフィールドを当サイトが直接引いて作成(観測時点 2026-09-08 06:20 JST)。- ・対象は4パッケージのみ:
feishu-docx-mcp@0.3.2/blueai-cli@0.7.0/bmc-i18n-extract-cli@1.1.1/bmc-translate-utils@1.1.1。@antvエコシステムは今回の対象ではない - ・公開は1.206秒間のバースト:4版すべてが 2026-09-07 09:25:00.253〜09:25:01.459 UTC に公開された。人手ではなく自動化スクリプトの実行である
- ・すでに全パッケージが削除済み:npmセキュリティチームが同日 13:50 UTC に差し押さえた。露出は約4時間25分(パッケージごとに数秒差)
- ・露出時間帯(JST):2026-09-07 18:25〜22:50 JST。この時間帯に該当パッケージを取得していなければ、本件による直接の影響は考えにくい
- ・5月19日の波との同一性:AikidoはSHA-256の一致を根拠に挙げるが、そのハッシュ値を公表しているのはAikidoだけだ。一方で同社が挙げるC2ドメインは、本記事が5月時点から記載している
t.m-kosche.comと一致する - ・脆弱性データベースは未登録:観測時点でOSVは4パッケージとも該当0件、GitHub Advisoryにも登録が無い
- ・日本の読者の実害はほぼゼロ:4パッケージとも日本語での検索需要は計測下限(SV 0)。本節の価値は自分の被害確認ではなく、手口のパターンにある
何が公開されたか——レジストリ実測
各パッケージの公開時刻・削除時刻・直前の正規版は以下のとおり。すべて https://registry.npmjs.org/<パッケージ名> のpackumentの time フィールドから取得した値だ。
| パッケージ | 悪性版 | 公開(UTC) | 直前の正規版 | 前版からの間隔 |
|---|---|---|---|---|
bmc-translate-utils |
1.1.1 |
09:25:00.253 | 1.0.1(2025-09-08) |
363日 |
blueai-cli |
0.7.0 |
09:25:00.506 | 0.6.0(2026-08-26) |
11日 |
feishu-docx-mcp |
0.3.2 |
09:25:00.552 | 0.2.2(2026-03-20) |
171日 |
bmc-i18n-extract-cli |
1.1.1 |
09:25:01.459 | 1.0.1(2025-09-08) |
363日 |
ここで2つの「休眠」を混同しないでほしい。Aikidoが言う111日はペイロード(ハッシュ)が観測されなかった期間であり、上表の11〜363日は各パッケージが更新されなかった期間だ。両者は別の指標で、後者は11日から363日までばらついている。つまり「放置されたパッケージだけが狙われた」わけではなく、11日前まで正常に更新されていた blueai-cli も同じバーストに含まれている。乗っ取られたアカウントが、活発なパッケージと事実上放棄されたパッケージを両方所有していた——という読み方のほうが実測に合う。Aikidoは4パッケージが「同一のnpmアカウントから公開された」としているが、アカウント名は同社も公表しておらず、削除後のpackumentからは確認できない(後述)。
なお4版ともマイナーバージョンの繰り上げで公開されている(0.2.2→0.3.2、1.0.1→1.1.1、0.6.0→0.7.0)。Aikidoが記述する「tarball取得→ペイロード注入→バージョン繰り上げ→再公開」というサイクルと整合する。
すでに削除済み——npmセキュリティチームによる差し押さえ
Aikidoの記事はパッケージが削除されたかどうかに触れていない。当サイトがレジストリを引いた時点では、4パッケージとも既にnpm側の操作で取り下げられていた(後述するプレースホルダの形式から、npmセキュリティチームによる差し押さえと判断できる)。
| パッケージ | 取り下げ(UTC) | 露出時間 |
|---|---|---|
blueai-cli |
13:50:14 | 4時間25分14秒 |
bmc-i18n-extract-cli |
13:50:20 | 4時間25分19秒 |
bmc-translate-utils |
13:50:26 | 4時間25分26秒 |
feishu-docx-mcp |
13:50:30 | 4時間25分30秒 |
npm側の操作と判断する証拠は3点そろっている。第一に、4パッケージとも現在の全バージョンが 0.0.1-security ただ1つで、その description は security holding package、repository は npm/security-holder になっている。これはnpmがセキュリティ上の理由でパッケージを取り下げたときに置く定型のプレースホルダだ。第二に、maintainers が空配列になり、公開者が npm <npm@npmjs.com> に置き換わっている。第三に、悪性版のtarball(例: feishu-docx-mcp-0.3.2.tgz)はHTTP 404を返す。
重要なのは、悪性版だけでなく過去の正規版もまとめて消えている点だ。blueai-cli は28バージョンを持っていたが、現在レジストリに残るのは 0.0.1-security だけである。したがってこれらのパッケージに依存していたプロジェクトは、悪性版を踏んでいなくても次の npm ci が404で失敗する。その失敗自体は感染のサインではない——正規版まで消えたことによる副作用なので、切り分けを誤らないでほしい。
- ・確かめたこと:npmレジストリのpackument(公開時刻・バージョン一覧・dist-tags・maintainers・repository)、悪性版tarballのHTTPステータス、OSV APIとGitHub Advisory APIの登録状況、DataForSEOによる各パッケージ名の日本語検索ボリューム、および後述の確認コマンドの挙動(自作のフィクスチャで陽性・陰性の対照つき)
- ・確かめていないこと:ペイロードそのもの。悪性版は既に削除されておりtarballを取得できないため、SHA-256の一致・C2通信・永続化の挙動はいずれも当サイトで再現していない。これらはAikidoの報告として出典を示して引用しており、独立検証ではない
- ・やっていないこと:4パッケージのインストール(
npm install/npxのいずれも実行していない)。攻撃コードは再現可能な形で掲載しない
5月19日の波との同一性——ハッシュは単一ソース、C2は複数ソースで一致
ここは慎重に切り分ける必要がある。Aikidoは同一性の根拠としてSHA-256ハッシュ e37e3dd…5b1a6 を挙げているが、当サイトが確認した限り、このハッシュ値を公表しているのはAikidoだけだ。5月19日の波を報じたSocketの記事にハッシュの記載は無く、この値をWeb検索しても一致するページは出てこない。つまりハッシュによる同一性は、現時点では他社の観測で裏が取れていない単一ソースの主張である。
一方で、同一性を支持する別経路の証拠は存在する。Aikidoが今回のC2として挙げる t.m-kosche.com は、5月19日の@antv事件についてSocket・StepSecurity・JFrog・Chainguard・Snykが揃って報告し、本記事も5月時点から https://t.m-kosche.com:443/api/public/otel/v1/traces というエンドポイントまで記載してきたものと一致する。Dune用語を組み合わせた公開リポジトリ名という特徴も両方の波に共通する。
したがって当サイトの立場は次のとおりだ。「同じC2インフラを使う同系統の攻撃」は複数ソースで裏が取れる事実であり、「バイト単位で同一のペイロード」はAikido1社の報告である。この2つを同じ強さで書くべきではない。
@antv 323パッケージ・639版
C2: t.m-kosche.com"] -->|"111日間 ハッシュの観測なし"| B["2026-09-07 09:25 UTC
4パッケージ・1.206秒のバースト"] B --> C["2026-09-07 13:50 UTC
npmセキュリティチームが差し押さえ
露出 約4時間25分"] A -.->|"複数ソースで一致(事実)"| D["C2ドメイン
t.m-kosche.com"] B -.->|"Aikido1社のみ(未裏取り)"| E["SHA-256
e37e3dd…5b1a6"]
自分の環境を確認する——対照群で検証したコマンド
以下のコマンドは掲載前に自作のフィクスチャで陽性・陰性の両方を実際に確認した。悪性版は既に削除されているため、手元で実行しても何も出ないのが正常だが、「何も出ない=コマンドが正しい」ではない。壊れたコマンドも同じように沈黙するからだ。そこで、4パッケージを仕込んだツリー(陽性対照)と、紛らわしい名前 blueai-cli-helper だけを置いたクリーンなツリー(陰性対照)の両方に当てて、前者では検出し後者では沈黙することを確認している。
Step 1 — ロックファイルの確認
grep -nE '(feishu-docx-mcp|bmc-i18n-extract-cli|blueai-cli|bmc-translate-utils)["@]' \
package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null
末尾の ["@] は飾りではない。これを外すと、無関係な blueai-cli-helper のようにパッケージ名を前方に含むだけの正常なパッケージにも一致してしまう(陰性対照で実際に誤検出することを確認した)。package-lock.jsonでは名前の直後が "、pnpm-lock.yaml・yarn.lockでは @ になるので、この1文字で名前の終端を固定できる。
ただし固定しているのは終端だけで、先頭は固定していない。そのため @someorg/blueai-cli のようなスコープ付きの別パッケージにも一致する(スコープ付きのフィクスチャで実際に一致することを確認した)。先頭も固定しようとすると、今度はpnpm-lock.yamlの字下げされた行を取りこぼして陽性対照が壊れることも実測で確認したので、ここは意図的に緩いままにしてある。過検出であって見落としではない——一致した行にスコープ(@…/)が付いていれば、それは本節の対象パッケージではないので、出力を目視で確認してほしい。
上のコマンドを
if grep -q …; then の形でCIに組み込んではいけない。yarn.lock が無いプロジェクト(npmのみの構成では普通のこと)では、grepはマッチの有無に関わらず終了コード2を返す。実測では、4パッケージを仕込んだツリーでもクリーンなツリーでも等しく2だった(3つのロックファイルが揃っている場合のみ 0/1 が正しく返る)。判定は終了コードではなく出力の有無で行う。Step 2 — node_modules に実体が残っていないかの確認
find node_modules -type d \
\( -name feishu-docx-mcp -o -name bmc-i18n-extract-cli \
-o -name blueai-cli -o -name bmc-translate-utils \) \
-exec grep -H '"version"' {}/package.json \;
find の -name はディレクトリ名の完全一致なので、blueai-cli-helper は対象外になる(陰性対照で確認済み)。また node_modules を起点にした再帰なので、node_modules/<親>/node_modules/blueai-cli のように推移的依存として深い位置に入った実体も検出できる(陽性対照にネストした複製を仕込んで確認した)。ここで版が表示され、それが上表の悪性版と一致した場合のみ、本節の対象となる。
Step 3 — 露出時間帯との突き合わせ
検出された場合は、そのインストールが 2026-09-07 18:25〜22:50 JST(09:25〜13:50 UTC)のビルドで行われたかをCIログで確認する。この時間帯の外で取得した実体は、悪性版ではない可能性が高い(ただし版番号が一致するなら悪性版と考えるべきだ)。該当した場合の対処は「6. 緊急対処手順」がそのまま使える——シークレットのローテーションを最優先に、t.m-kosche.com への通信有無をログで確認する順序は5月の波と変わらない。
脆弱性データベースはまだ沈黙している
観測時点(2026-09-08 06:20 JST)で、OSVは4パッケージとも該当0件、GitHub Advisory Databaseのnpm向け新着にも該当は無かった。5月19日の波でも@antv事件の直後は同様の空白があり、これは本サイトが8月のnpm事案でも繰り返し実測してきたパターンだ。発生直後の安全証明にスキャナの緑を使わない——この原則は今回も当てはまる。
なお今回に限っては、パッケージ自体がレジストリから消えているため、仮にアドバイザリが登録されても npm audit が参照する現在の依存ツリーには一致しない可能性がある。前掲のコマンドによるロックファイル・実体の直接確認のほうが確実だ。
この波の射程——手口のパターンとして読む
正直に書いておくと、日本の読者がこの4パッケージを使っている可能性は極めて低い。DataForSEOで実測した日本語検索ボリュームは feishu-docx-mcp・blueai-cli とも0(計測下限)で、いずれもニッチなツールだ。@antv事件が週約110万ダウンロードの echarts-for-react を巻き込んだのとは規模が2桁以上違う。
それでも本節を追記したのは、同じC2インフラが4か月近く経っても稼働しており、同系統の攻撃が単発で終わっていないことが、5月の波を読んだ読者にとって重要だからだ。5月時点で t.m-kosche.com をブロックし、ignore-scripts=true を入れ、トークンをローテーションした組織は、その対策が今も無駄になっていないことになる。逆に「5月の騒ぎは終わった」として元に戻した組織は、同じ経路が再び開いている。本節の実務的な含意はそこにある。
まとめ
- ・2026-05-19、@antvメンテナアカウント
atoolが乗っ取られ、323パッケージ・639バージョンに Mini Shai-Hulud ペイロードが注入された。 - ・echarts-for-react(週110万DL)・timeago.js(週150万DL)など @antv名前空間外も含む広範囲が対象だ。
- ・preinstallフック→難読化index.js→20種以上の認証情報収集→AES-256-GCM暗号化送信、という同一ファミリーの攻撃チェーンが確認された。
- ・ワーム化機能により被害者の管理パッケージにも混入して再拡散し、2200以上のGitHubリポジトリが既に窃取トークンで作成された。
- ・BreachForumsでのソースコード公開により攻撃の「民主化」が進み、今後も同種の攻撃が増加する可能性が高い。
- ・今日中にできる対策として「CI/.npmrcでignore-scripts=true」「lock ファイル確認」「シークレットローテーション」の3点を優先する。
今回の事件は、メンテナアカウントのセキュリティという根本的な弱点を突いたものだ。コード署名・npm provenanceがあっても「正規のメンテナのアカウントが乗っ取られた」場合には無力であることが改めて示された。npmエコシステム全体として、メンテナアカウントへの2FA強制・ハードウェアキー必須化・アカウント監視の仕組みを強化することが急務となっている。
参照ソース
- Aikido Security — A Shai-Hulud npm payload came back 111 days later(2026-09-07の再浮上の初報)
- Socket Threat Research — Active Supply Chain Attack Compromises @antv Packages on npm
- StepSecurity — Shai-Hulud: Here We Go Again. Mass npm Supply Chain Attack Hits the AntV Ecosystem
- Wiz Research — The Worm That Keeps on Digging: TeamPCP Hits @antv in Latest Wave
- OX Security — The @antv Ecosystem Was Compromised with Shai-Hulud Malware, 300+ Packages Affected
- SafeDep — Mini Shai-Hulud Strikes Again: 317 npm Packages Compromised