12 人が閲覧(直近 30 日) 脆弱性・インシデント

s1ngularityとは?Nx侵害の2段階の手口とAI CLI悪用、CVE-2025-10894の確認・対応手順

s1ngularityとは?Nx侵害の2段階の手口とAI CLI悪用、CVE-2025-10894の確認・対応手順

「s1ngularity」は、2025年8月にビルドツールNxの公式npmパッケージが改ざんされたサプライチェーン攻撃の呼び名です。日本時間8月27日の朝から昼にかけて配布された悪性版は、インストール時に開発端末の認証情報を集め、被害者自身のGitHubアカウントに公開リポジトリを作って置いていきました。端末にあるClaude・Gemini・Amazon QのCLIに秘密情報の探索を指示した点で、StepSecurityは、開発者向けAIアシスタントをサプライチェーン攻撃に悪用した初の既知の事例と報告しています。この記事では、Nx公式アドバイザリとWiz・GitGuardianの分析をもとに、侵入の2段階の仕組み、AIに渡されたプロンプトと成功率、被害規模、確認と対応の手順、GitHub Actionsの安全な書き方を扱います(2026年11月7日時点)。

まとめ:s1ngularity攻撃で確定した事実と今すぐ確認すべき点

  • 何が起きたか:Nxのリポジトリにあった脆弱なGitHub Actionsワークフローを足がかりにnpmトークンが盗まれ、nxと公式プラグインの悪性版が公開された。悪性版は認証情報を集め、被害者のGitHubに s1ngularity-repository を含む名前の公開リポジトリを作った。
  • 識別子:GHSA-cxm3-wv7p-598c(2025年8月27日公開)とCVE-2025-10894(CNAのRed HatによるCVSS v3.1は9.6)。GitHub Advisory Database側の勧告は2026年7月28日に取り下げ表示になり、Dependabotのアラートは出ない。
  • 配布時間:nx系は2025年8月27日7:32〜11:44(日本時間)。@nx/keyと@nx/enterprise-cloudは同日19:20まで残っていた。
  • AIの悪用:版によってAIに渡すプロンプトが3種あった。Wizの集計では、被害者の約半数がAI CLIを入れていたが、AI経由で流出に成功したのは4分の1未満だった。
  • 被害規模:第2段階で少なくとも480アカウントが6,700超のプライベートリポジトリを公開された(Wiz)。GitGuardianは10,767リポジトリ・82,901シークレットの露出と集計している。
  • 今すぐ確認:/tmp/inventory.txt があれば感染している。GitHubのsecurity logは直近90日分しか表示されないため、2025年8月の repo.create は当時保存したログで確認する。gh CLIのアプリのアクセスを取り消してトークンを作り直す。

s1ngularityとは:Nx公式パッケージの改ざんと識別子の現状

Nx公式のセキュリティアドバイザリによると、nxパッケージと一部の公式プラグインに、ファイルシステムを走査して認証情報を集め、利用者のGitHubアカウントにリポジトリとして投稿するコードが入った版がnpmに公開されました。名前は、マルウェアが作ったリポジトリ名 s1ngularity-repository に由来します。英単語singularity(シンギュラリティ)の「i」を数字の「1」に置き換えた表記です。

識別子の扱いは公開後に変わっています。NVDのCVE-2025-10894は2025年9月24日に公開され、CNAのRed HatがCVSS v3.1で9.6(Critical)と評価しました。NVD自身の評価は付かず、状態は「Deferred」のままです。GitHub Advisory Databaseの勧告は2026年7月28日の更新で @nx/key 5.0.7 を対象に加え、同時刻に取り下げ(Withdrawn)の表示になりました。5.0.7は2026年5月22日公開の版で、Amazon Inspectorの検知によりOpenSSFのmalicious-packagesにある @nx/key の記録(MAL-2025-41440)へ3.2.0と並んで追加されました。この記録は、誤検知の取り下げをまとめたPR #1276で5月26日(UTC)に記録ごと withdrawn へ移されています。3.2.0が悪性版だった事実は変わりませんが、GitHub側の勧告全体を取り下げた理由は公表されていません。取り下げられた勧告ではDependabotのアラートが出ないため、影響の確認はNx公式アドバイザリの版一覧で行います。

悪性版と配布時間帯:影響を受けたNxパッケージの一覧

悪性版はNx本体と公式プラグインで、いずれもnpmレジストリから削除済みです。時刻はNx公式のタイムライン(EDT)を日本時間に換算しています。

パッケージ 悪性版
nx 20.9.0・20.10.0・20.11.0・20.12.0
nx 21.5.0・21.6.0・21.7.0・21.8.0
@nx/devkit・@nx/js 20.9.0・21.5.0
@nx/node・@nx/workspace 20.9.0・21.5.0
@nx/eslint 21.5.0
@nx/key 3.2.0
@nx/enterprise-cloud 3.2.0

nxの悪性版は表の8つで、プラグインを含めるとNx公式の一覧では合計19の版になります。範囲ではなく版番号で照合してください。たとえば21.6.1〜21.6.11や21.5.1・21.5.2は事件後に公開された正常版で、npm ls nx で21.6系が出ても、それだけでは感染の証拠になりません。最初の公開は8月26日18:32 EDT(日本時間8月27日7:32)、npmによる削除は22:44 EDT(同11:44)、@nx/keyと@nx/enterprise-cloudの削除は8月27日6:20 EDT(同19:20)でした。

VS Code用の拡張機能Nx Consoleの18.6.30〜18.65.1は、版の確認のために nx@latest をインストールする動作を持っていました。悪性版が latest だった日本時間8月27日7:37〜11:44にこの拡張を入れたエディタを起動しただけで、Nxを使うプロジェクトが無くても感染しえます。修正版は18.66.0で、JetBrains版は対象外です。Nxそのものの機能と運用はNx monorepoの機能と導入手順で解説しています。

侵入の仕組み:PRタイトルのインジェクションからnpmトークン窃取まで

PR検証のbashインジェクションとpull_request_targetの書込権限

原因は、2025年8月21日16:31 EDT(日本時間22日5:31)にマージされた、PRタイトルの形式を検証するワークフローです。run: の中で ${{ github.event.pull_request.title }} をそのままechoしていたため、$(...) を含むタイトルのPRを開くとコマンドが実行されました。トリガーは pull_request_target で、通常の pull_request と違い、PRの送り先である nrwl/nx の書き込み権限を持つ GITHUB_TOKEN 付きで、送り先ブランチにあるワークフローの版で動きます。チームは翌22日にmasterで差し戻しましたが、古いブランチには脆弱なワークフローが残っており、攻撃者は古いブランチを宛先にPRを作ったとNxは見ています。

publish.ymlを起動させてnpmトークンを持ち出した2段目の仕組み

誤解されやすいのはここです。Nx公式によると、PR検証ワークフロー自体はシークレットを持っていませんでした。攻撃者はその書き込み可能な GITHUB_TOKEN で、別のワークフロー publish.yml を起動させました。publish.yml はNxのパッケージを公開するパイプラインで、GitHub Secretとしてnpmトークンを持っています。悪性のコミットで書き換えられた publish.yml が、そのnpmトークンを外部のwebhookへ送信しました。

タイムラインでは、8月24日16:50 EDT(日本時間25日5:50)にトークンをwebhookへ送るコミット、17:04にそのコミットを含むPRの作成、17:11に publish.yml の実行記録の削除が監査ログに残っています。同じくGitHub Actionsを経路にした事案はtj-actions/changed-files侵害とreviewdog侵害の経緯で扱っています。

postinstallで動いたマルウェアの収集・流出・妨害の挙動

悪性版の postinstall スクリプト(telemetry.js)は、LinuxとmacOSで動きました。Socketの解析によると、gh auth token でGitHubトークンを、~/.npmrc からnpmの認証情報を取り、環境変数を丸ごと集めたうえで、AI CLIに作らせたファイル一覧に載ったファイルの中身も読み込みます。Windowsでは process.platform === 'win32' の判定で即座に終了します。集めた情報は2重・3重のbase64でエンコードされ、results.b64 として被害者のGitHubに作った公開リポジトリへ置かれました。さらに ~/.bashrc と ~/.zshrc に sudo shutdown -h 0 を追記し、ターミナルを開くたびにパスワードを求め、入力するとマシンが停止する妨害も仕込みました。

AI CLIの悪用:版ごとに変わったプロンプトと実際の成功率

Claude・Gemini・Qを確認省略フラグ付きで呼び出す仕組み

マルウェアは端末にClaude、Gemini、Amazon QのCLIがあると、それぞれを確認を省くフラグ付きで起動しました。Wizの続報が公開したコードでは、呼び出し方は次の3通りです。

claude --dangerously-skip-permissions -p "<PROMPT>"
gemini --yolo -p "<PROMPT>"
q chat --trust-all-tools --no-interactive "<PROMPT>"

AIにさせたのはファイルの場所の一覧作りで、結果は /tmp/inventory.txt に書かせました。中身の読み取りと送信はマルウェア本体が行います。感染の目印が /tmp/inventory.txt なのはこのためです。

版ごとに3種あったプロンプトの違い

Wizによると、悪性版には少なくとも3種のペイロードがあり、版ごとにプロンプトと作るリポジトリ名が違います。

nxの版 プロンプトの書き方 作成リポジトリ
20.9.0・20.11.0・21.5.0 ウォレット・鍵のパターンを列挙して探索 s1ngularity-repository
21.6.0・21.7.0 「許可を得たペネトレーションテスト」と役割を指定 s1ngularity-repository-0
20.12.0・21.8.0 「ファイル検索エージェント」として設定ファイルを探索 s1ngularity-repository-1

2つ目の版で入った「penetration testing」という語は、AI側の拒否としてはっきり表れたとWizは報告しています。3つ目では攻撃を連想させる語が消え、ソースコードを除外して設定ファイルだけを探す指示に変わりました。

Wizの集計に見るAI経由の流出の成功率

同じ続報は、AIによる探索が成功するまでの各段階で大きく脱落したと集計しています。被害者のうちAI CLIを1つ以上入れていたのは約50%で、多くはClaudeでした(Gemini約15%、Q約5%)。Claudeへの依頼は4分の1近くが拒否され、Geminiでは4分の1近くが作業ディレクトリ外を読めない既定の制限で止まりました。探索がNxのディレクトリだけで終わった例も多くあります。AI経由で流出に成功したのは4分の1未満で、流出した2万ファイルのうち有効なシークレットは100件未満でした。

この数字から引き出せる判断は2つです。AIのガードレールは攻撃を一部止めましたが、決定的ではなく、プロンプトを変えれば通る前提で考えるべきです。もう1つは、GitHubトークン・npmトークン・環境変数はAIを使わずに本体が直接集めていた点です。GitGuardianが数えた2,349件のシークレットは別の調査標本で有効性を問わない集計のため、AI経由の割合は出せませんが、AIが失敗しても本体の収集は止まりません。AI CLIだけを対策の焦点にすると、本筋のトークン管理が手薄になります。

マルウェアは確認省略フラグを自分で付けてAI CLIを呼び出すため、利用者がフラグを既定にしないだけでは防げません。AIプロセスが読めるファイルと認証情報を実行環境の側で絞ることが本筋で、そのうえで共有の開発端末やCIで --dangerously-skip-permissions や --yolo を既定にする運用もやめるべきです。Snykの勧告も、AIコーディングエージェントのファイルとネットワークへのアクセスを制限するよう求めています。AIエージェントの権限設計や導入時のリスク評価を外部に相談したい場合は、AIセキュリティ対策で対応できます。実行前に操作を止めるフックはClaude Code Hooksのイベントと設定方法、AIで攻撃自体を組み立てる型のマルウェアはAI駆動型マルウェアの実例と防御策、エラー文でエージェントを乗っ取る手口はAgentjackingの攻撃と防御設定で扱っています。

被害規模:3段階で広がったリポジトリ公開と漏洩した認証情報

被害は3段階に分かれます。数値は集計した組織と時点で異なります。

段階 内容 規模(出典)
第1段階 悪性版が認証情報を公開リポジトリへ 1,079端末・2,349件(GitGuardian)
第2段階 盗んだトークンで非公開リポジトリを公開 480アカウント・6,700超(Wiz)
第3段階 2ユーザーが1組織のリポジトリを公開 500超(Wiz)

GitGuardianの分析では、第1段階で盗まれた2,349件のうち1,100件超が有効なままで、攻撃者はそれを使って10,767のプライベートリポジトリを公開し、82,901件のシークレットを露出させました。感染端末の85%はmacOSです。第2段階の規模は、Wizの初報では400超のユーザー・組織と5,500超のリポジトリでしたが、続報で少なくとも480アカウント(約3分の2が組織)・6,700超に増えました。第3段階は8月31日夜からで、リポジトリは説明文「S1ngularity」と接尾辞 _bak 付きで公開されています。

漏洩したGitHubトークンは8月28日朝(UTC)にほぼ90%が有効で、29日夕方でも約80%が有効でした。GitHubが一斉失効した後に約5%まで下がっています。

影響を確認する:Nx公式アドバイザリの手順とコマンド

感染の痕跡を調べるコマンド

次のコマンドはmacOS・Linuxのシェルを想定しています。1〜4は読み取りだけです。

# 1) 感染の痕跡:このファイルがあれば影響を受けている(マルウェアが読んだファイルの一覧)
ls -la /tmp/inventory.txt

# 2) 使っている nx の版を確認する(悪性版なら即座に更新)
npm ls nx

# 3) シェル設定に追記された shutdown を探す(見つかったら該当行を手で削除)
grep -n "shutdown -h 0" ~/.bashrc ~/.zshrc

# 4) 自分のアカウントに s1ngularity 名のリポジトリが残っていないか(組織は gh repo list 組織名)
gh repo list --limit 1000 | grep -i s1ngularity

# 5) 悪性版を入れていた場合:更新とキャッシュ削除(公式手順)
npm uninstall nx && npm install nx@latest
npm cache clean --force
yarn cache clean --all
pnpm store prune --force
rm -rf ~/.npm/_npx

GitHubの個人security logの表示対象は直近90日間です。2026年11月時点で2025年8月の事案を調べる場合は、当時エクスポートしたログなどの保存記録で action:repo.create を検索し、s1ngularity-repository を含むリポジトリが作られていないかを確認します。GitHubが先に削除している場合もあり、その場合の問い合わせ先はGitHubサポートです。残っていれば記録用にファイルを保存してから削除し、漏れた内容の復号方法はNxの窓口([email protected])に問い合わせるよう案内されています。Windowsのnpxキャッシュは %LocalAppData%\npm-cache\_npx にあります。

gh CLIを含むトークンの入れ替え

見落としやすいのがgh CLIです。公式手順では、gh CLIが認証に使うGitHubのアプリ(ID 178c6fc778ccc68e1d6a)のアクセスを設定画面から取り消し、次に gh を実行したときに再認証して新しいトークンを発行します。そのうえで、npmトークン、GitHubのパスワードとトークン、環境変数に置いていた他のサービスの認証情報もすべて入れ替えます。社内レジストリ(JFrog ArtifactoryやSonatype Nexusなど)を運用している場合は、悪性版を削除して社内からの再ダウンロードを止めてください。

2026年に更新するときの版と移行

事件直後のNxは正常版の21.4.1を latest に戻しましたが、2026年11月7日時点のnpmの latest は24.0.5(11月6日公開)です。公式手順の npm install nx@latest をそのまま打つと、20系・21系から24系へメジャー版を飛び越えます。Nxの更新ガイドは1メジャーずつの移行を勧めており、Angularを含むワークスペースでは必須としています。21系からなら、まず系列内の最終版へ上げ、22系、23系、24系の順に進めます。各段階では、npx nx migrate <移行先の版> で移行内容を生成し、更新された依存関係を使用中のパッケージマネージャーでインストールしてから、npx nx migrate --run-migrations で適用する手順を踏みます。メジャー版を上げられない事情があるなら、各系列の最終版に留める選択もあります。20系の最終は20.8.4(2026年1月12日公開)で、悪性版の20.9.0〜20.12.0より番号が小さい点に注意が要ります。21系の最終は21.6.11(2026年4月17日公開)です。

再発防止:GitHub Actionsのワークフローとnpm公開の認証

外部入力を環境変数で渡すPR検証ワークフロー

教訓は2つです。外部入力をワークフローのシェルに直接埋め込まないこと、そして強い権限を持つワークフローを別のワークフローから起動できる経路を残さないことです。GitHub Actionsのセキュリティ使用リファレンスは、信頼できない入力は式で直接展開せず、環境変数を経由させるよう勧めています。

# PRタイトルの検証を安全に書く例(.github/workflows/pr-title.yml)
on:
  pull_request:            # 外部PRの検証には pull_request_target ではなく pull_request を使う
    types: [opened, edited, synchronize, reopened]
permissions:
  contents: read           # GITHUB_TOKEN を読み取りだけに絞る
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - name: Validate PR title
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}   # 式は env に入れるだけにする
        run: |
          # 例として Conventional Commits 形式のタイトルを検証する
          title_pattern='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([[:alnum:]_.-]+\))?!?: .+$'
          if [[ ! "$PR_TITLE" =~ $title_pattern ]]; then
            printf '%s\n' 'PR title does not match the required format.'
            exit 1
          fi
          printf 'Valid PR title: %s\n' "$PR_TITLE"

環境変数として渡せば、タイトルに $(...) が含まれていてもシェルはコマンドとして解釈しません。pull_request_target がどうしても必要な場合は、PR側のコードをチェックアウトしない、permissions を最小にする、古いブランチにも同じ修正を入れる、の3点を守ります。Nxはmasterだけを直し、古いブランチに脆弱なワークフローを残したことで侵入を許しました。GITHUB_TOKEN の既定権限の絞り方はGitHub Actionsのpermissionsと最小権限の設計、シークレットの置き場所はGitHub ActionsのSecrets管理とOIDC移行の判断で整理しています。

2026年12月2日からの公開リポジトリでのpull_request_target既定ブロック

Nxの侵入口になった pull_request_target は、GitHub側で既定の扱いが変わります。GitHubの2026年11月2日のchangelogによると、2026年12月2日から、すべての公開リポジトリで pull_request_target イベントが既定でブロックされ、Actionsのイベントポリシーで明示的に許可したものだけが動きます。当初の予定は11月2日でした。対象はGitHub Free・Team・Enterprise Cloudの公開リポジトリで、非公開・社内リポジトリとGitHub Enterprise Serverは対象外です。

本適用の前に、11月9日と11月16日の16:00〜18:00(UTC、日本時間は翌日1:00〜3:00)に一時的なブロックが行われ、該当するワークフローは失敗の実行記録とエラー注記を残して止まります。公開リポジトリでこのトリガーを使っているなら、先にInsightsでブロックされる実行を確かめ、本当に必要なワークフローだけをファイル単位で許可する形に絞るのが筋です。Nxの事案と同じ型のワークフローは、既定のままなら12月2日以降は動きません。

これとは別に、actions/checkout v7(2026年6月18日に一般提供)は、pull_request_target と workflow_run でフォークのPRのコードを取得する操作を既定で拒否します。v1を除く既存のメジャー版にも7月20日に同じ動作が入りましたが、SHAやパッチ版で固定しているワークフローは対象外です。ただし、Nxの侵入はフォークのコードのチェックアウトではなく、PRタイトルの式展開によるものでした。checkoutの拒否だけでは同じ穴は塞がらず、上の環境変数で渡す書き方が別に要ります。

npm公開のTrusted Publishingへの移行

Nxは事後にnpmの公開トークンを破棄し、Nx社の全パッケージで2FAを必須にしてアクセストークンでは公開できない設定にし、nxの公開をTrusted Publisher(OIDCによる公開)へ移しました。外部の貢献者が起動するワークフローはメンバーの承認を必須にし、CodeQLも有効にしています。npm側も、2025年11月5日から書き込み権限を持つgranularトークンの有効期限を最長90日に制限し、新しく作る書き込み用トークンでは2FAを既定にしました。12月9日にはclassic tokenが全件失効し、npm login で得られるのは2時間で切れるセッショントークンに変わっています。さらにnpmのドキュメントは、granularトークンで新しい版を直接公開する機能を2027年1月に廃止すると告知しており、自動化はステージ専用トークンと npm stage publish による承認制か、Trusted Publishingへ移すよう求めています。長期のnpmトークンをCIのシークレットに置いたままの運用は、もう選ぶ理由がありません。

組織の初動:漏洩から失効までの時間を縮める体制

漏洩したトークンの多くは丸1日以上有効なまま残り、その間に第2段階の悪用が進みました。被害の大きさを決めるのは、漏洩から失効までの時間です。CIには実行時の通信監視(StepSecurityのHarden-Runnerなど)を入れておくと、npm install 中に api.github.com へリポジトリを作る通信のような異常を検知できます。npm・GitHub・クラウドのトークンを誰がどの順で失効させるかは、平時に手順書にしておきます。

「Nxを直接使っていないから関係ない」とも言えません。Nx Consoleや推移的な依存、AIエージェントによる自動インストールのように、利用者が意識しない経路で悪性版は入ってきます。開発端末に置く認証情報を最小限にし、AIコーディングツールに使わせてよいフラグを利用規程に書いておくことが、同型の攻撃への備えになります。

その後の続報:Shai-Hulud以降に続いたnpmサプライチェーン攻撃

s1ngularityの直後、2025年9月には自己増殖型のワーム「Shai-Hulud」が現れ、米CISAは9月23日のアラートで500以上のパッケージが侵害されたと注意を呼びかけました。盗んだnpmトークンで別のパッケージを汚染して広がる点で、s1ngularityより一段進んだ攻撃です。その後も2.0、Mini、CHAINDROPと続き、Claude Codeの設定ファイルに起動フックを仕込む手口まで現れました。経緯と確認方法はShai-Huludの各波と影響確認・対策、起点別の類型はサプライチェーン攻撃の起点別3類型にまとめています。

よくある質問

s1ngularity攻撃の識別子、影響確認、AI CLIの対策について、2026年11月7日時点の公開情報で答えます。

s1ngularityのCVE番号と深刻度は?

CVE-2025-10894です。CNAのRed HatによるCVSS v3.1の評価は9.6(Critical)で、NVD自身の評価は付いていません。GitHub上の識別子はGHSA-cxm3-wv7p-598cで、一次情報はNxが2025年8月27日に公開したアドバイザリです。GitHub Advisory Database側の勧告は2026年7月28日に取り下げ表示になっており、Dependabotのアラートには頼れません。

s1ngularityの読み方と名前の由来は?

「シンギュラリティ」と読みます。英単語singularityの「i」を数字の「1」に置き換えた表記で、マルウェアが被害者のGitHubに作ったリポジトリ名 s1ngularity-repository から、この攻撃の呼び名になりました。リポジトリ名には -0 や -1 が付く変種もあります。

自分が影響を受けたかどうかはどう確認しますか?

/tmp/inventory.txt があれば影響を受けています。加えて npm ls nx で表の悪性版と版番号が一致しないか、当時保存したGitHubのsecurity logに s1ngularity-repository を含む repo.create が無いか(表示は直近90日分なので、今のログに無くても未感染とは言えません)、~/.bashrc と ~/.zshrc に sudo shutdown -h 0 が無いかを確かめます。

Nxを使っていないのに感染することはありますか?

あります。VS Code用のNx Console 18.6.30〜18.65.1は版の確認のために nx@latest をインストールしていたため、日本時間2025年8月27日7:37〜11:44にこの拡張を入れたエディタを起動すると感染しえました。修正版は18.66.0です。推移的な依存やAIエージェント経由のインストールも経路になりえます。

AIのCLIツールを使っている開発者が気を付けることは?

AI CLIが読めるファイルと認証情報を、実行環境の側で絞ることです。s1ngularityのマルウェアは確認を省くフラグ(--dangerously-skip-permissions、--yolo、--trust-all-tools)を自分で付けてAI CLIを呼び出したため、利用者がフラグを既定にしないだけでは防げません。Wizの調査ではClaudeへの依頼の4分の1近くが拒否されましたが、プロンプトを変えれば通る前提で考えます。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

資料請求

RELATED POSTS 関連記事

目次