
Nxの “s1ngularity “NPMサプライチェーン攻撃に関する調査で、数千のアカウントトークンとリポジトリの秘密が流出し、大規模な被害が明らかになりました。
Wizのリサーチャーによるインシデント後の評価によると、Nxの侵害により、3つの異なるフェーズで2,180のアカウントと7,200のリポジトリが流出しました。
Wizはまた、流出した秘密の多くが依然として有効であるため、インシデントの影響範囲は依然として大きく、その影響はまだ拡大していると強調した。
Nxの “s1ngularity “サプライチェーン攻撃
Nxは人気のあるオープンソースのビルドシステムとmonorepo管理ツールで、企業規模のJavaScript/TypeScriptエコシステムで広く使用されており、NPMパッケージインデックスで毎週550万以上のダウンロードがある。
2025年8月26日、攻撃者はNxリポジトリのGitHub Actionsワークフローの欠陥を悪用し、インストール後のマルウェアスクリプト(’telemetry.js’)を含む悪意のあるバージョンのパッケージをNPM上で公開しました。
telemetry.jsマルウェアは、LinuxおよびmacOSシステムを標的とした認証情報窃取ツールで、GitHubトークン、npmトークン、SSHキー、.envファイル、暗号ウォレットを窃取し、”s1ngularity-repository “という名前の公開GitHubリポジトリに秘密をアップロードしようとしました。
この攻撃が際立っていたのは、LLMプロンプトを使用して機密性の高い認証情報と秘密を検索し、収穫するために、Claude、Q、Geminiなどの人工知能プラットフォーム用のインストール済みコマンドラインツールを使用する認証情報窃盗犯がいたことです。

出典:Wiz:Wiz
Wizの報告によると、プロンプトは攻撃を繰り返すたびに変化しており、脅威行為者がより成功しやすいようにプロンプトをチューニングしていたことを示しています。
「プロンプトの進化は、攻撃者が攻撃全体を通してプロンプトのチューニングを急速に探っていたことを示しています。私たちは 役割プロンプトとウィズ氏は説明する。
「これらの変更は、マルウェアの成功に具体的な影響を与えました。例えば、”侵入テスト “というフレーズの導入は、LLMがそのような活動に従事することを拒否することに具体的に反映された。
大規模な爆発半径
攻撃の第一段階では、8月26日から27日にかけて、バックドアされたNxパッケージは1,700人のユーザーに直接影響を与え、2,000以上のユニークな秘密が流出した。この攻撃はまた、感染したシステムから20,000のファイルを流出させた。
GitHubは8時間後に攻撃者が作成したリポジトリを削除することで対応したが、データはすでにコピーされていた。
Wizがフェーズ2と定義する8月28日から29日にかけて、攻撃者は流出したGitHubトークンを使って非公開のリポジトリを公開に切り替え、「s1ngularity」という文字列を含むようにリネームした。
この結果、さらに480のアカウント(大半は組織)が侵害され、6700の非公開リポジトリが公開された。
8月31日に始まった第3段階では、攻撃者は1つの被害者組織を標的とし、侵害された2つのアカウントを利用して、さらに500のプライベート・リポジトリを公開しました。

ソースはこちら:Wiz
Nxの対応
NxチームはGitHubで詳細な根本原因分析を発表し、プルリクエストのタイトルをインジェクションする方法と、pull_request_targetの安全でない使い方とが組み合わさったことが攻撃の原因であると説明しています。
これにより、攻撃者は昇格したパーミッションで任意のコードを実行することができ、Nxのパブリッシュパイプラインがトリガーされ、npmパブリッシングトークンが流出しました。
悪意のあるパッケージは削除され、漏洩したトークンは失効してローテーションされ、すべてのパブリッシャーアカウントで二要素認証が採用されました。
このような侵害の再発を防ぐため、Nxプロジェクトは現在、トークンベースのパブリッシングを排除するNPMのTrusted Publisherモデルを採用し、PRトリガーのワークフローに手動承認を追加しています。
.ia_ad { background-color:#width: 95%; max-width: 800px; margin: 15px auto; border-radius: 8px; border:1px solid #d6ddee; display: flex; align-items: stretch; padding: 0; overflow: hidden; }:0; overflow: hidden; } .ia_lef { flex: 1; max-width: 200px; height: auto; display: flex; align-items: stretch; } .ia_lef a { display: flex; width: 100%; height: 100%; } .ia_lef a img { width: 100%; height: 100%; object-fit: cover; border-radius: 8px 0 0 8px; margin: 0; display: block; } .ia_rig { flex: 2; padding:display: flex; flex-direction: column; justify-content: center; } .ia_rig h2 { font-size: 17px !important; font-weight: 700; color:#line-height: 1.4; font-family:margin: 0 0 14px 0; } .ia_rig p { font-weight: bold; font-size: 14px; margin: 0 0 clamp(6px, 2vw, 14px) 0; } .ia_button { background-color:#border:1px solid #3b59aa; color: black; text-align: center; text-decoration: none; border-radius: 8px; display: inline-block; font-size: 16px; font-weight: bold; cursor: pointer; padding:width: fit-content; } .ia_button a { text-decoration: none; color: inherit; display: block; } @media (max-width: 600px) { .ia_ad { flex-direction: column; align-items: center; } .ia_lef { max-width: 100%; } .ia_lef a img { border-radius: 8px 8px 0 0; } .ia_rig { padding:15px;
width: 100%;
}
.ia_button {
width: 100%;
margin: 0px auto;
}
}




Comments