Shai-Hulud「Trinitite」ワーム、人気npmパッケージTanStack Queryに感染し開発者の機密情報を窃取

Shai-Huludサプライチェーン攻撃の新たな亜種「Trinitite」が、TanStack Query用のコード生成ライブラリで週間150,000件以上のダウンロード数を誇るnpmパッケージ@7nohe/openapi-react-query-codegenを侵害しました。

この悪意あるリリースは、開発者情報、クラウド、CI/CD、パッケージレジストリ、Kubernetes、Vault、ソースコード管理の各種認証情報を窃取したうえで、奪取したアクセス権を使ってさらに他のパッケージへ拡散するよう設計された進化型のMini Shai-Huludワームを展開します。

今回のサンプルは、これまでの「Here We Go Again」、5月19日の@antv、Miasmaの各波状攻撃とツールや拡散挙動、運用パターンを共有していますが、確認されたペイロードだけでは攻撃者の帰属を断定するには至っていません。

注目すべき変化としては、リリースチェーンの悪用、新規に生成されたRSA鍵、新たなキャンペーン用文字列、そして隠蔽されたbinding.gyp実行経路が挙げられます。

侵害の発端は、危険なGitHub Actionsリリースワークフローの設定にありました。このプロジェクトは、プルリクエストのコメントに「npm publish」という正確な文言が含まれていれば、それをリリース実行の承認として扱っていたのです。

ワークフローはそのプルリクエストをチェックアウトし、GitHub ActionsのOIDC(id-token: write権限付き)を使ってリリースを公開していましたが、コメント投稿者がリポジトリのメンテナーであるかどうかの確認は行っていませんでした。

p00pabootという名前のGitHubアカウントが、悪意あるプルリクエストを開いてリリースのトリガーを発行したとみられています。これにより、ワークフローは正当な信頼済みトークン(trusted-publishing token)を発行し、有効なプロベナンス(来歴証明)付きの成果物を生成してしまいました。

今回の事例は、プロベナンスが証明するのはあくまで「成果物がどこでビルドされたか」であり、「信頼されたリリース環境内で攻撃者が制御するコードが実行されたかどうか」までは証明しないという事実を、改めて浮き彫りにしています。

攻撃者はまず2つのプレリリース版を公開しました。最初の0.0.0-365d4eb…には、Bunをインストールし、存在しないファイルis_it_this_simple.jsを起動しようとする不審なpreinstallコマンドが含まれていました。

この時点では最終的なペイロードは含まれていませんでしたが、環境変数にはすでに、意図するワークフローと標的パッケージが記されていました。

続く8つの安定版リリース(0.5.4、0.5.5、1.6.3、1.6.4、2.2.1、2.2.2、3.0.3、3.0.4)に、実際のワームが仕込まれていました。

技術面で最も重要な変化は、悪意あるbinding.gypファイルの使用です。

最初の一連の安定版はこのファイルのみに依存していましたが、その約20分後に公開されたリリースでは、node 3FWCvzduYZg.jsを呼び出す従来型のpreinstallスクリプトも追加されていました。

JFrog Security Researchによれば、このキャンペーンは2026年8月28日に検知されており、これはTeamPCPに関連する人物がオーストラリアで逮捕されたと報じられた8月下旬の直後にあたります。

3FWCvzduYZg.jsは4MBから6MB規模の、XOR難読化が施されたローダーです。npm install –ignore-scriptsを使えば表向きのpreinstallフックは抑制できますが、node-gypが仕込まれたbinding.gypファイルを評価する際に、この脅威は依然として実行され得ます。

Shai-Hulud「Trinitite」ワーム

攻撃者は、条件分岐(conditions)ステートメント内にUnicodeエスケープされたPythonコードを埋め込む形でコマンドを隠していました。デコードすると、その式はPythonの組み込み関数に到達し、os.system(‘node 3FWCvzduYZg.js’)を実行します。

Image

node-gypはconditionsをPython経由で処理するため、package.jsonのライフサイクルスクリプトのみを検査するセキュリティツールでは、この悪意ある実行チェーンを見逃してしまう可能性があります。

InstallingSecurity Systems

このローダーは、XORキー9を使って整数配列をデコードし、2つのAES-128-GCM暗号化データを復号したうえで、必要に応じてBun v1.4.0をダウンロードし、復号したワームを一時的なJavaScriptファイルから実行します。

ペイロードはその後、この一時ステージファイルを削除します。内部モジュールにはさらなる難読化が施されており、200,000ラウンドのPBKDF2-SHA256、AES-256-GCM暗号化、gzip圧縮された組み込みコンポーネントが用いられています。

Trinititeは有効化されると、GitHub、npm、PyPI、RubyGems、クラウドの認証情報、Vaultトークン、Kubernetes関連情報、SSH鍵、Dockerの認証情報、CI/CDのシークレットを標的にします。

また、Runner.Workerのメモリから「isSecret」:trueとマークされた値をスクレイピングすることも可能で、これにはディスクに一度も保存されない可能性のある認証情報も含まれます。

窃取されたデータは圧縮・暗号化され、RSAでラップされたうえで、被害者のトークンを使って作成された攻撃者管理下の公開GitHubリポジトリにコミットされます。

このワームには、npmの公開権限を取得できたパッケージを再公開するロジックも組み込まれています。

GitHub Actions環境では、窃取したOIDC情報をnpm公開用の認証情報と交換できるため、Shai-Huludを単なる認証情報窃取ツールではなく、自己増殖するパッケージワームたらしめるフィードバックループが形成されています。

Trinititeは、Shai-Hulud特有の破壊的なトークン失効トラップも維持しています。LinuxおよびmacOS環境では、systemd-detect-fashやsysvinit-detect-fashといった名前で永続化を仕込むほか、~/.local/share/diaper/poopy.pyというパスにPython製の監視プログラムを配置します。

監視対象のGitHubトークンが無効化されると、仕込まれたハンドラーがユーザーのホームディレクトリおよび~/Documentsの削除を試みる可能性があります。

影響を受けるバージョンをインストールしてしまった組織は、まず該当する開発者用ワークステーションまたはCIランナーを隔離し、永続化の仕組みを停止・除去してから、認証情報の失効手続きを行うべきです。

防御担当者は、3FWCvzduYZg.js、binding.gyp、Frot、dog.c、trinnyyyy-*、/var/tmp/.shit、そして名称を変更された「ClaudeCode Review」というGitHub Actionsワークフローがインストール環境やビルド成果物に存在しないか確認する必要があります。

各チームは、既知の安全なリリースである0.5.3、1.6.2、2.2.0、3.0.2にパッケージを固定し、信頼できるソースからロックファイルを再生成したうえで、侵害の可能性があるランナーを再構築し、クリーンな環境からGitHub、npm、PyPI、RubyGems、クラウド、SSH、Kubernetes、Vault、CI/CDの各認証情報をローテーションすべきです。

IOC(侵害指標)

パッケージ Xray ID バージョン
@7nohe/openapi-react-query-codegen XRAY-1065308 0.5.40.5.51.6.31.6.42.2.12.2.23.0.33.0.40.0.0-365d4eb738d3146583431948d3ba6e27a32556be0.0.0-ec7876d6c917dad516ba69bbfafc948b834bf0ab

注記: IPアドレスおよびドメインは、誤って名前解決やリンク化されることを防ぐため、意図的に無害化(例: [.])してあります。再度有効な形式に戻す作業は、MISP、VirusTotal、あるいは各自のSIEMなど、管理された脅威インテリジェンス基盤の中でのみ行ってください。

★ 削減すべきセキュリティツールをどう見極めるか? 1ページで採点する方法 – 「継承されたセキュリティスタック」ガイドをダウンロード

InstallingSecurity Systems

翻訳元: https://gbhackers.com/shai-hulud-trinitite-worm/

本記事は gbhackers.com の記事を翻訳・要約したものです。