世界を動かす技術を、日本語で。

自己増殖型NPMマルウェアが40以上のパッケージを侵害

2025年9月16日原文(stepsecurity.io)

概要

  • NPMエコシステム で新たなサプライチェーン攻撃が発生
  • @ctrl/tinycolor など40以上の人気パッケージが侵害対象
  • マルウェアは 自己伝播機能 を持ち、依存パッケージを連鎖的に感染
  • 認証情報の収集・外部送信、永続化のためのGitHub Actionsワークフロー挿入
  • 影響パッケージや 検知方法・インジケーター を詳細解説

NPMサプライチェーン攻撃の概要と進化

  • @ctrl/tinycolor を含む40以上のNPMパッケージでマルウェア感染
  • 週200万ダウンロード超 の人気パッケージが標的
  • マルウェアは 自己増殖型エンジン 搭載、下流パッケージを自動感染
  • postinstallスクリプト を悪用し、npm install時に不正コード実行
  • Linux/macOS開発環境 を主なターゲット、Windowsは回避

攻撃チェーンとマルウェアの構造

  • Webpackバンドル(bundle.js) による複数モジュール構成
  • process.env から認証情報を抽出、クラウドSDK/API利用で情報収集
  • TruffleHog を用いたファイルシステム全体のシークレットスキャン
  • 自己伝播 :NpmModule.updatePackage関数でメンテナーパッケージへ連鎖感染
  • GitHub Actionsワークフロー (shai-hulud-workflow.yml)を自動生成し永続化

マルウェアの詳細技術分析

  • OS情報収集 :getSystemInfo()でプラットフォーム・アーキテクチャ情報取得
  • AWS認証情報収集 :AssumeRoleWithWebIdentityCommand経由で検証・Secrets Managerから秘密情報を列挙
  • GCP認証情報収集 :@google-cloud/secret-managerで全シークレット取得・ペイロード復号
  • ファイルシステムスキャン :TruffleHogで高エントロピーなシークレット(AWSキー等)検出
  • NPMトークン取得・自己増殖 :.npmrcや環境変数からNPM_TOKEN抽出、所有パッケージを自動パッチ&公開

GitHub・クラウド認証情報の悪用と外部送信

  • GitHubバックドア :/userエンドポイントで認証、全リポジトリにshai-huludブランチ作成
  • ワークフロー挿入 :pushイベントで秘密情報をC2サーバへ送信
  • JSON形式で全情報集約、GitHub APIで"Shai-Hulud"公開リポジトリにアップロード
  • エラーはcatch {}で黙殺、TruffleHog実行を「セキュリティスキャン」と偽装

検知・対応のためのインジケーター

  • shai-hulud-workflow.yml の存在確認:.github/workflows/配下を検索
  • shai-huludブランチ の有無:ghコマンド等で全リポジトリを調査
  • bundle.js SHA-256 :46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
  • 外部送信先 :https://webhook.site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7
  • API/プロセス挙動 :NpmModule.updatePackage、AWS/GCP/NPM/GitHub APIへの異常アクセス、TruffleHogやnpm publish --forceの実行履歴

影響を受けたパッケージ一覧(一部抜粋)

  • @ctrl/tinycolor 4.1.1, 4.1.2
  • angulartics2 14.1.2, 14.1.1
  • @ctrl/ngx-codemirror 7.0.2, 7.0.1
  • @ctrl/ngx-csv 6.0.2, 6.0.1
  • @nativescript-community/gesturehandler 2.0.35
  • ngx-color 10.0.2, 10.0.1
  • ngx-toastr 19.0.2, 19.0.1
  • react-complaint-image 0.0.35, 0.0.32
  • ts-gaussian 3.0.6, 3.0.5
  • その他、40以上のパッケージ

組織での検知・対応策

  • GitHub検索 でshai-hulud-workflow.ymlやshai-huludブランチを徹底調査
    • 例:org:ACME path:/shai-hulud-workflow.yml
  • 全リポジトリのブランチ一覧取得、shai-huludブランチの存在確認スクリプト
  • bundle.jsのハッシュ値 でファイル照合
  • 不審なAPIアクセス・プロセス実行履歴 の監査
  • 感染パッケージの即時アンインストール・クリーンインストール推奨

まとめ・今後の注意点

  • NPMサプライチェーンの脅威 は高度化・自動化傾向
  • メンテナ権限の乗っ取り によるエコシステム全体への波及リスク
  • クラウド認証情報・GitHubシークレット の漏洩による二次被害懸念
  • 依存パッケージの監査・アップデート と、CI/CD環境のセキュリティ強化が必須
  • 継続的な脅威インテリジェンス収集 と、検知・対応体制の整備が重要

Hackerたちの意見

残念ながら、こういうサプライチェーン攻撃は現代のJavaScriptエコシステムに組み込まれてるってことを実感してきたよ。ベンダリングで即座のリスクは軽減できるけど、根本的な問題は解決しない。これがサーバーレンダリング(JSなし)をもっと真剣に考えるきっかけになったかも。HTMXの人たちに、JavaScriptなしでもかなりのことができるって納得させられたし、アプリも多分速くて、ゴチャゴチャしないと思う。

VueJs(JSON AjaxレスポンスをUIに変換するJavaScriptライブラリ)とHtmx(HTML AjaxレスポンスをUIに変換するJavaScriptライブラリ)の開発依存関係の数の違いって意味あるの?違いはあるけど、桁違いってわけじゃないし、どちらも完全に独立してるわけじゃない。サーバーでJSを使わないって決めるのはこの記事の文脈では合理的だけど、クライアント側ではhtmxも他のJSライブラリと同じように(開発)依存関係があるよ。 https://github.com/bigskysoftware/htmx/blob/master/package.j... https://github.com/vuejs/core/blob/main/package.json

私の見たところ、この攻撃が依存しているのは、新しい依存関係を追加する際の開発者のチェック不足だけだね。このチェック不足がJavaScriptエコシステムに特有のものでない限り、この攻撃はRustやGolangでも起こり得たと思う。

マルウェアを取りに行くまで、サプライチェーン攻撃はパッケージ管理やマシンへのベクトル、コードのあらゆるレイヤーで起こるよ。NPMが本当に気にしてるなら、公開するのに2FAを必須にするべきだね。公開前にスキャンを要求する。パッケージにハードキーと署名で署名する。インストールされた全てのパッケージが署名と一致するか確認する。セマンティックバージョニングの一致だけじゃ不十分だし、CRCチェックも足りない。これをパッケージとパッケージ管理に組み込む必要がある。

残念ながら、こういうサプライチェーン攻撃は現代のJavaScriptエコシステムに組み込まれてるってことを実感してきたよ。 こういう奇妙な見解をよく見るけど、攻撃の範囲を最近起こった単一のエコシステムに自動的に狭めるのは、技術的な根拠がないよね。特に懸念すべきは、セキュリティ業界でこういう見解が見られること。例えばNPMをターゲットにした対策が講じられているけど、PyPiやCratesには全くない。これが奇妙なのは、そうすることで他のエコシステムが無防備になるだけじゃなく、対策は非常に似ているはずだから、大きな利益のために最小限の追加労力で済むのに。

JavaScriptは過剰に使われすぎてるし、依存されすぎてる。多くのウェブサイトはテキストや画像を表示するだけなのに、みんなが知ってるからって重いJavaScriptライブラリを使ってる。これが現代のウェブを支えるトラッキングを可能にするからね。ユーザーにとってのメリットはないし、もし本当にJavaScriptを使わざるを得ない選択肢がなければ、こういうサイトが存在しない方がいいと思う。

そうだよ。パッケージマネージャーに依存しすぎて、標準ライブラリがない言語はこういうのに脆弱だね。いつか人々は気づいて、バニラJSに戻る必要があると思うけど、それはかなり難しいだろうな。Rustエコシステムも同じだし。パッケージへの依存が多すぎる。正しくやってる例はGoだね。

伝統的なJSは実は今まで作られた中で最も安全な環境の一つなんだ。毎日、何十億ものデバイスが信頼できないJSコードを実行していて、他のプラットフォームではこんなに大規模なサンドボックス実行は見られない。ほぼ30年の間に、ブラウザエンジンに対する大規模な攻撃はほとんどなかった。それが、ブラウザから派生したJSエンジンをサーバーサイドフレームワークを作るための完璧なツールにしている。ただ、NodeJSやnpmのプロセスや実践はセキュリティの見直しが急務だね。leftpadは解決すべき文化的な問題だよ。まずは、スニペットはnpmに置く必要はない。

単にJavaScriptを避けるだけじゃダメだよ。npmは大きくて簡単なターゲットだけど、一般的な問題はすべてのパッケージリポジトリに存在するからね。攻撃者が使ってないパッケージリポジトリを狙うのを期待するより、サプライチェーン攻撃の緩和戦略を考えた方がいいと思う。JavaScript開発の文化では、抽象化を重ねるコストを無視する風潮があるけど、それに乗っかる必要はないよ。多分、一番簡単なのは遷移依存関係を数えることだね。

npmの「postinstall」って概念があるせいで、影響範囲がさらに悪化してるんだよね。これによって、インストール後にホストシステムでコマンドを実行できるパッケージが増えちゃう。依存関係の依存関係にもこれが適用されるから、node_modules内の何でもこのフックにアクセスできるんだ。これはひどいアイデアで、削除するかもっと安全なものに置き換えるべきだと思う。

サプライチェーン攻撃 OSSに関しては、この用語を使うのはやめた方がいいよ。サプライチェーンって関係を示唆するけど、これらの企業や開発者はパッケージを含める以外にクリエイターとの関係はないから。「フリーコード攻撃」とか「ホビイストコード攻撃」みたいな名前にした方がいい。

左パッドの騒動の時、ここであるコメント者が有名なnpmのメンテナーについて「600のnpmパッケージの作者で、1200行のJavaScriptを書いている」って言ってたのを覚えてる。その後あまり変わってないよね。私が知ってる最良の反例はesbuildで、これは完全な機能を持つバンドラー/ミニファイアで、Goの標準ライブラリとGoプロジェクト自身がメンテナンスしている1つのパッケージ以外は外部依存関係がゼロだよ。 https://www.npmjs.com/package/esbuild?activeTab=dependencies https://github.com/evanw/esbuild/blob/755da31752d759f1ea70b8... 他の「次世代」プロジェクトは、問題のあるエコシステムを別のものに置き換えているだけ。例えばbiomejsやswcの依存関係を調べると、結構良さそうだよ。 https://www.npmjs.com/package/@biomejs/biome/v/latest?active... https://www.npmjs.com/package/@swc/types?activeTab=dependenc... eslintの炎上(数百から数千の依存関係)をゼロに置き換えるのはすごく励みになるけど、Rustのソースを見つけると... https://github.com/biomejs/biome/blob/a0039fd5457d0df18242fe... https://github.com/swc-project/swc/blob/6c54969d69551f516032... こういうプロジェクトがもっと勢いを増すと、cargoエコシステムでも似たようなことが起こると思う。esbuildと同じくらい厳格なスタイルで書かれた他の大きなプロジェクトを知ってる人いる?

Hacker Newsで議論の続きを見る