ソフトウェアのサプライチェーン攻撃とは?入口の型と 2026 年の実例(axios・Trivy・TanStack)

PR
ソフトウェアのサプライチェーン攻撃とは?入口の型と 2026 年の実例(axios・Trivy・TanStack)
この記事は約32分で読めます。

ソフトウェアのサプライチェーン攻撃は、ソフトウェアを作って届ける途中(作り手の環境や、配る道筋)に悪いコードを入れ、そのソフトを使う人に届けてしまう攻撃です。サプライチェーンは「供給の連なり」のことで、ここでは、自分のアプリが頼っているライブラリや道具と、それを作って配る仕組みの連なりを指します。

この記事では、2026年に当事者(そのソフトを作っている側)が事後報告を出した axios・Trivy・TanStack の件などを、「どこから入られたか」という入口の型ごとに整理します。そのうえで、npm や GitHub Actions を使う人が何を見ればよいかをまとめます(2026年10月時点)。手順そのものは、npm・yarn・pnpm の記事と GitHub Actions の記事に任せ、ここでは要点だけを書きます。Web 開発で点検することの全体は、同じ時期に出すWeb 開発のセキュリティの基本にまとめています。

この記事でわかること
  • 「ソフトウェアの」サプライチェーン攻撃とは何か。IPA 10大脅威の「サプライチェーンや委託先を狙った攻撃」とは範囲が違うこと
  • 乗っ取りの入口の 5 つの型と、型ごとの実例(盗まれた資格情報、タグの書き換え、インストール時のスクリプト、CI の設定の穴、配布物・ビルドの汚染〔xz utils〕)
  • 「信頼できる公開(trusted publishing)にすれば安全」とは言えない理由
  • Log4Shell が「乗っ取り」ではなく「部品の穴」である理由
  • 自分のプロジェクトで見る所(lock ファイル・インストール時のスクリプト・workflow の依存の固定・資格情報)と、手元で流した出力

ソフトウェアのサプライチェーン攻撃とは?IPA の「サプライチェーンや委託先を狙った攻撃」との違い

公的機関の定義

米国の CISA(サイバーセキュリティを担当する政府機関)は、2021年4月に NIST(米国立標準技術研究所)と一緒に出した文書で、ソフトウェアのサプライチェーン攻撃を次のように説明しています。ソフトウェアの作り手のネットワークに攻撃者が入り、作り手が客に届ける前に、悪意のあるコードでそのソフトを侵害する。侵害されたソフトが、今度は客のデータやシステムを侵害する。最初から悪いものが入っていることも、パッチや修正版のような別の道で入ることもある。そして、そのソフトを使う人すべてに影響が及ぶ、という説明です(CISA の文書(PDF)・文書の紹介ページ)。

同じ文書は、よくある手口を 3 つ挙げています。更新の乗っ取り、コード署名の悪用、オープンソースのコードの汚染です。最後のものは、公開のライブラリに悪いコードを入れ、気づかない開発者が自分のコードに取り込んでしまう、というものです。2021年の文書なので、npm のワームや CI(コードを変えるたびに確かめて公開まで自動で行う仕組み)の話は載っていません。

OWASP Top 10:2025 では、A03「ソフトウェアサプライチェーンの不備」がこの話に当たります。ソフトウェアを作る・配る・更新する流れの破綻や侵害のことで、多くは、頼っている第三者のコード・道具・依存(ほかの部品への頼り)にある、脆弱性か悪意のある変更から起きる、と説明されています(OWASP Top 10:2025 A03(日本語版))。2013年の「既知の脆弱性のある部品を使う」から、既知の穴だけでなく、サプライチェーンの失敗の全部へ広がった項目です。

範囲が違う、IPA の 2 位

IPA(情報処理推進機構)の「情報セキュリティ10大脅威 2026」では、組織向けの 2 位が「サプライチェーンや委託先を狙った攻撃」です。名前が似ていますが、この項目は 2 つの繋がりを 1 つにまとめたものです(IPA 解説書[組織編](PDF))。

IPA の言い方中身
ビジネス上の繋がり商品の企画から開発、調達、製造、在庫管理、物流、販売までの一連のプロセスと、それに関わる組織や外部サービス取引先や委託先を通って入られる話
ソフトウェアの繋がり(ソフトウェアサプライチェーン)ソフトウェア開発のライフサイクルに関わる、ライブラリ・ツール・開発者・インフラなどの要素と、その繋がりこの記事が扱う話

IPA が挙げる攻撃手口は 3 つです。標的の関連会社や業務委託先を攻撃する、ソフトウェアの開発元のソフトにマルウェアを仕込んで利用者の機器を感染させる、MSP(運用や保守を請け負う事業者)が使う資産管理ソフトなどに仕込む、です。1 つ目が取引先を通る話で、2 つ目と 3 つ目がソフトウェアの話です。

この記事が扱うのは、IPA の 2 位の全部ではなく、ソフトウェアの繋がりの側だけです。なお、IPA のプレス発表(2026年1月29日)にある「取引先を含むサプライチェーン全体に深刻な影響を及ぼした事例」という文は、ランサムウェア(データを使えなくして金銭を要求する攻撃)の話の文で、ソフトの乗っ取りの話ではありません(IPA プレス発表)。2 位は 2019年に初めて選ばれ、2026年で 8 年連続 8 回目です。解説書の対策の欄には、納品物に入っているソフトウェアの把握に、SBOM(ソフトウェア部品表。どの部品を使っているかの一覧)の導入を検討する、とあります。

乗っ取りの入口は?5 つの型と 2026年の実例(2026年10月時点)

乗っ取りの「入口」は、いくつかの型に分けると整理しやすくなります。次の 5 つの分け方は、この記事で読みやすいように決めたもので、公的機関の分類ではありません。実例は、当事者の事後報告と、CISA・NVD(米国の脆弱性データベース)などの公的機関の文書に書かれている範囲だけを使います。攻撃の細かい手順や、悪い版を取りに行く方法は書きません。

型入口実例
1盗まれた資格情報(アカウントの乗っ取り)axios、Shai-Hulud、Trivy(3月19日の公開)
2タグの書き換え(GitHub Actions)tj-actions/changed-files、Trivy
3インストールのときに動くスクリプトShai-Hulud、TanStack
4CI の設定の穴TanStack
5配布物・ビルドの汚染xz utils

1 つの件が複数の型にまたがることがあります。Trivy は型 1 と型 2 の両方、TanStack は型 3 と型 4 の両方です。

型 1:盗まれた資格情報(アカウントの乗っ取り)

資格情報は、パスワードやトークン(パスワードの代わりに使う長い文字列)のように、「その人だ」と認めてもらうためのものです。メンテナー(ライブラリを保守して公開する人)の資格情報が盗まれると、攻撃者は正規の公開の手順で、悪い版を出せます。

axios(2026年3月31日)。 axios は JavaScript でよく使われる HTTP 通信のライブラリです。当事者の事後報告によると、1.14.1 と 0.30.4 の 2 つの悪い版が、リードメンテナーの乗っ取られたアカウントから npm に公開されました。どちらも plain-crypto-js@4.2.1 という依存を足し、それが macOS・Windows・Linux に遠隔操作のトロイの木馬(RAT)を入れました。悪い版は約 3 時間で消されています(axios の事後報告)。当事者は、元のコードを変えたのではなく、リードメンテナーのアカウントへの不正なアクセスによるものだ、と書いています。

入口についての当事者の説明は、リードメンテナーのパソコンが、狙い撃ちのソーシャルエンジニアリング(人をだます手口)と遠隔操作のマルウェアでやられ、そこから npm のアカウントの資格情報が取られた、というものです。ただし当事者は、確かな細部はまだ言えないとも書いています。この記事も、手口を広げません。反省として、個人のアカウントから直接公開していたのは避けられた危険だったこと、勝手な公開を自動で見つける仕組みが無く、気づくのはコミュニティ頼みだったことが挙げられています。CISA も 2026年4月20日に注意喚起を出しています(CISA の注意喚起)。

なお、悪い依存がインストール時のスクリプトで動いたのかどうかは、当事者の報告にも CISA の注意喚起にも書かれていません。そのためこの記事では、axios を型 3 ではなく型 1 に置いています。

Shai-Hulud(2025年9月)。 CISA は2025年9月23日、「Shai-Hulud」の名前で知られる、自分で広がるワーム(自己複製するプログラム)が、npm の 500 を超えるパッケージを乗っ取ったと注意喚起しました(CISA の注意喚起)。広がり方が、まさに型 1 です。GitHub の個人トークンと、AWS・Google Cloud・Azure などのクラウドの API キーを狙い、乗っ取った開発者として npm に認証し、ほかのパッケージにコードを入れて悪い版を公開しました。盗んだ資格情報で、次を乗っ取るわけです。数え方は資料で違い、CISA は「500 を超えるパッケージ」、OWASP は「500 を超える版」と書いています。

Trivy(3月19日の公開)。 Trivy は、コンテナなどの脆弱性を調べる道具です。NVD と当事者の告知は、2026年3月19日に攻撃者が、盗まれた資格情報で悪い Trivy v0.69.4 を公開した、と書いています。これは2026年2月下旬に始まった攻撃の続きでした。3月1日の公表のあとに資格情報の差し替えをしましたが、一度に全部ではなかった(not atomic)ため、差し替えの数日のあいだに、新しい秘密も盗めた可能性がある、と同じ文で説明されています(NVD: CVE-2026-33634・当事者の告知)。2月下旬の最初の入口は、NVD にも告知にも書かれていません。

当事者は、axios については「OIDC で公開する流れと、変えられないリリースを、この件より前に入れておくべきだった」、Trivy については「資格情報の差し替えが一度に全部ではなかった」と書いています。防ぐ手順は、あとの「防ぐには?」にまとめます。

型 2:タグの書き換え(GitHub Actions)

GitHub Actions では、他人が作った action(workflow に組み込める部品)を、uses: owner/repo@v1 のように、タグで指して使うことが多くあります。タグは、Git でコミット(変更の記録)に付ける名札です。名札は、後から別のコミットに付け替えられます。GitHub の公式文書も、action を置いたリポジトリに悪い人が入ると、タグは動かしたり消したりできる、と説明しています(GitHub Docs: 安全な使い方)。

tj-actions/changed-files(2025年3月)。 CVE-2025-30066 です。2025年3月14日から15日にかけて、v1 から v45.0.7 までのタグが攻撃者に書き換えられ、悪いコミットを指しました。CI/CD の秘密が workflow のログに出ました。v46.0.1 で直り、KEV(CISA の、悪用が確認された脆弱性の一覧)には2025年3月18日に載っています(NVD: CVE-2025-30066・GitHub Advisory)。

Trivy(2026年3月19日)。 v0.69.4 の公開に加えて、aquasecurity/trivy-action のタグ 77 個のうち 76 個を強制的に書き換え(force-push。すでにある名札を、強制で別のコミットに付け替えること)、aquasecurity/setup-trivy のタグ 7 個全部を悪いコミットに差し替えました。KEV には2026年3月26日に載っています。当事者の告知によると、悪いものが出ていた時間は、v0.69.4 が約 3 時間、trivy-action が約 12 時間、setup-trivy が約 4 時間です。3月22日には、Docker Hub に悪い v0.69.5・v0.69.6 の image も出て、約 10 時間でした。NVD の説明は3月19日の件までで、3月22日の件は当事者の告知にあります。

この件で、守られた版があります。当事者によると、変えられないリリース(GitHub の immutable releases)にしていた版は当たりませんでした。Trivy v0.69.3 と trivy-action 0.35.0 です。image を digest(中身のハッシュ)で指していた場合も当たりませんでした。

もう 1 つ、注意したいことがあります。コミットの SHA で固定していても、当たった場合がありました。 trivy-action を2025年4月9日より前のコミットに固定していた人は、trivy-action 自体は安全でも、その中で呼ばれる setup-trivy が、悪いものになりえました。trivy-action が setup-trivy を固定し始めたのが、2025年4月9日の変更だったためです。それより後の安全なコミットへの SHA の固定なら、当たりませんでした。NVD の勧めは、GitHub Actions を完全な、変わらないコミットの SHA に固定し、動かせる版のタグを使わないこと。タグで指していた人は、3月19日から20日の workflow の実行ログを確かめることです。GitHub の公式文書(2026年10月20日に確認)は、第三者の action へのいちばんの手当てとして、workflow の依存の lockfile での固定を挙げ、使えないリポジトリでは完全な SHA での固定を挙げています。くわしくは、あとの「防ぐには?」とGitHub Actions の記事にあります。

型 3:インストールのときに動くスクリプト

npm のパッケージは、入れたときに自動で動くスクリプト(preinstall・install・postinstall など)を持てます。便利な仕組みですが、悪いコードを入れた版があると、入れた人の手元(開発者のパソコンや CI)で、そのまま動いてしまいます。

Shai-Hulud は、乗っ取ったメンテナーのアカウントから、人気のパッケージに悪意のある post-install スクリプト(入れた直後に動くスクリプト)を入れて広がりました(GitHub のブログ)。OWASP は、このスクリプトが秘密のデータを集めて公開の GitHub リポジトリに出し、見つけた npm のトークンで、触れるパッケージの悪い版を自動で公開した、と書き、「開発者自身がいまや主な標的」とまとめています。

TanStack の悪い版も、npm install・pnpm install・yarn install で入れると、ライフサイクルスクリプト(prepare)が動き、手元の資格情報(AWS・GCP・Kubernetes・Vault・~/.npmrc・GitHub のトークン・SSH の秘密鍵など)を集めました(TanStack の事後報告)。

CISA は axios のとき、.npmrc に ignore-scripts=true を書いて、インストール中に悪意のあるスクリプトが動くのを防ぐよう勧めました。インストール時のスクリプトを止める設定は、各ツールの既定も含めて、あとの「防ぐには?」で触れます。

型 4:CI の設定の穴(TanStack)

TanStack(2026年5月)。 CVE-2026-45321 です。2026年5月11日の 19:20〜19:26(UTC)に、42 個の @tanstack/* パッケージの 84 の悪い版が npm に公開されました。ここが、ほかの型と大きく違います。公開は、正規の GitHub Actions の OIDC(trusted publisher)を通っていて、公開の workflow そのものは書き換えられていません。 NVD は、攻撃者が 3 つの既知の穴の型を鎖にして、信頼された身元で、資格情報を盗むマルウェアを公開した、と説明します(NVD: CVE-2026-45321)。KEV には2026年5月27日に載り、CVSS(深刻度の点数)は GitHub が付けた 9.6(CRITICAL)です。

3 つの穴は次のとおりです。

  1. pull_request_target の設定の穴("Pwn Request")。pull_request_target は、外部の人が出した pull request でも、GITHUB_TOKEN(workflow に渡される一時的な鍵)に読み書きの権限が付いた状態で workflow を動かせるきっかけです
  2. フォークと本体のあいだの、Actions のキャッシュの汚染。フォークは、他人が自分のところに複製したリポジトリです
  3. ランナー(workflow を動かす機械)のメモリからの、OIDC トークンの取り出し

当事者の事後報告によると、この 3 つのどれか 1 つだけでは成り立ちませんでした。pull_request_target だけなら、ラベル付けやコメントのような信頼できる操作には問題ありません。フォークの pull request のコードが本体のキャッシュへ、本体のキャッシュがリリースの workflow へ、リリースの workflow が npm への書き込みへ、と信頼の境目を 1 つずつ越えたから、鎖が成り立ちました。GitHub の公式文書も、pull_request_target と workflow_run は、信用できない pull request のコードを checkout(取り込む)すると、リポジトリを危険にさらす、要らなければ pull_request_target を使わない、と書いています。理由は、これらの workflow が、本体のキャッシュを共有し、書き込みの権限や秘密に届くことがあるためです(GitHub Docs: 安全な使い方・workflow の書き方)。詳しくはGitHub Actions の記事にあります。

TanStack の事後報告には、見落としが 2 つあったと書かれています。TanStack の workflow を書いた人は、信用しない側には読み取りだけの権限を渡す形に分けようとしていました。しかし、actions/cache の、ジョブのあとのキャッシュの保存は、permissions: では止まりません(キャッシュの書き込みは、ランナーの中のトークンを使い、workflow の GITHUB_TOKEN ではないため)。permissions: contents: read にしても、キャッシュの書き換えは止まりません。もう 1 つは、キャッシュがリポジトリごとで、pull_request_target の実行と main への push で共有されることです。

事後報告は、npm のトークンは盗まれていない、公開の workflow も破られていない、と書いています。悪い版は、公開から 20〜26 分で外部の研究者に見つかりました。

「信頼できる公開」にすれば安全、ではありません

ここで、よくある読み違いに注意してください。npm の trusted publishing(信頼できる公開)は、CI から OIDC(ID を確かめる標準の仕組み)で公開し、長く使える npm のトークンを要らなくするものです(npm Docs: trusted publishers)。長く使えるトークンが盗まれる危険は減ります。しかし、TanStack の件が示したのは、公開が正規の trusted publisher を通っていても、悪い版は出せたということです。

TanStack 自身の反省にも、そのことが書かれています。

  • OIDC の trusted publisher には、公開 1 回ごとのレビューが無い。一度設定すると、workflow のどの道筋からでも、公開できるトークンを作れる
  • 中の見張りが無く、第三者からの知らせで知った
  • pull_request_target の workflow を、長く知られた危ない形なのに見直していなかった
  • 他人の action を、動く参照(@v6.0.2・@main のような指し方)で指していたのは、この件と別に続く危険だった

出どころの証明(provenance)についても同じです。npm の provenance は、どこでどう作られ、誰が公開したかを公に示せる仕組みです。ただし npm の文書は、provenance があっても、悪いコードが無いことまでは保証しないと書いています。ソースと作り方への、確かめられるつながりをくれるだけで、信じるかどうかは開発者が決める、という位置づけです(npm Docs: provenance)。

つまり、trusted publishing と provenance は大事な備えですが、「これにしたから安全」とは言えません。CI の設定(型 4)の穴が残っていれば、正規の道筋で悪い版を出せてしまうことがあります。

なお、npm の文書は、trusted publishing で公開に使うトークンは、短い期間だけ有効で、workflow に固有で、取り出して使い回すことはできない、と書いています。一方、NVD と TanStack の事後報告は、ランナーのメモリから OIDC のトークンを取り出した、と書いています。この 2 つの文が指すトークンが同じものかは、確かめられていません。そのため、どちらが正しいとも決めずに並べています。

TanStack の反省には、消すまでの時間もあります。事後報告の表によると、84 の版すべてを非推奨(deprecate。使わないよう印を付けること)にしたのは、最初の公開から約 1 時間 43 分でした。同じ報告の冒頭には「1 時間以内に非推奨にした」と読める文もありますが、ここでは表の数字を使っています。npm が最後の 1 つを消したのは約 4 時間 35 分です。ほとんどのパッケージで、依存しているパッケージがあると unpublish(公開の取り下げ)できない npm の決まりのため、npm の担当に消してもらうしかなく、そのあいだ悪い版は入れられる状態でした。

型 5:配布物・ビルドの汚染(xz utils)

xz(2024年3月)。 xz utils は、データ圧縮のソフトで、Linux の配布に入っていることがあります。CISA は2024年3月29日、5.6.0 と 5.6.1 に悪いコードが埋め込まれていた(CVE-2024-3094)と注意喚起し、5.4.6 Stable のような汚染されていない版に戻すよう勧めました(CISA の注意喚起)。

NVD によると、悪いコードは配布用の tarball(リリースの圧縮ファイル)に入っていました。ソースの中のテスト用のファイルに見せかけたものから、ビルドの途中で組み込まれる作りでした。CVSS は 10.0 です(NVD: CVE-2024-3094)。

xz のメンテナーのページによると、5.6.0 と 5.6.1 の tarball は、もう 1 人の保守役が作って署名したものでした。そして、引き金のコードは Git のリポジトリに一度も入っていません(xz のメンテナーのページ)。つまりこの件は、配られた圧縮ファイルの中身と、Git のリポジトリの中身が、一致していませんでした。メンテナーの見直しの記録では、裏口の準備の最初のコミットは2024年1月のもの(コミット日)とされています。もう 1 人の保守役は、5.2.12 と 5.4.3〜5.4.6 の tarball も作って署名していましたが、こちらは悪い中身は無いと確かめられています(見直しの記録)。

この件を「何年かけて仕込まれたのか」は、当事者・CISA・NVD のどの文書にも書かれていないので、この記事では年数を書きません。

Log4Shell は乗っ取りとは別?「部品の穴」との違い

サプライチェーンの話では、Log4Shell もよく並べて語られます。ただ、これは乗っ取りではなく、部品の穴の話です。起き方が違うので、分けて理解しておくと、対策の考え方も整理しやすくなります。

Log4Shell(CVE-2021-44228、2021年12月)は、Java のログのライブラリ Apache Log4j2 の脆弱性です。NVD の説明によると、設定・ログのメッセージ・パラメータで使われる JNDI の機能が、攻撃者の用意した LDAP などの先を防げませんでした。そのため、ログの文字を操れる人が、LDAP サーバーから読み込んだ任意のコードを動かせました。CVSS は 10.0 で、KEV にも2021年12月10日に載っています(NVD: CVE-2021-44228)。Apache の告知によると、当たるのは log4j-core の JAR だけで、log4j-api だけを使うアプリは当たりません(Apache Log4j のセキュリティ情報)。JPCERT/CC は、Log4j が動くサーバーに、遠隔の第三者が細工したデータを送ると、任意のコードが動く可能性があると注意喚起しました。どの版なら安全かは、版の範囲が資料で少し違うため、ここでは版の範囲は書きません。JPCERT/CC の最後の更新(2022年1月4日)は、2.17.1(Java 8 以降)・2.12.4(Java 7)・2.3.2(Java 6)が公開されたと追記しています(JPCERT/CC の注意喚起)。

CVE の記録に付いている弱点の分類(CWE)を見ると、違いがはっきりします。

乗っ取り(xz・Trivy・TanStack)部品の穴(Log4Shell)
何が起きたか作り手の手元や、配る道筋に、悪いコードが入れられた正しく配られた部品に、作りの穴があった
CVE の記録にある CWECWE-506(埋め込まれた悪意のあるコード)CWE-917(式言語の注入)、CWE-20(入力の検証の不備)、CWE-400(資源の使いすぎ)、CWE-502(信用できないデータの逆シリアル化)
案内された対応(CISA・NVD・当事者・Apache)汚染されていない版に戻す、資格情報を取り替える直った版に上げる

CWE は、ソフトウェアの弱点の種類に付けられた番号です(CWE-506 の説明)。付けた機関は、件によって違います。乗っ取りの 3 件の CWE-506 は、xz が Red Hat、Trivy と TanStack が GitHub の付けたもので、NVD 自身が付けたものではありません。Log4Shell は、NVD が CWE-917、Apache が CWE-20・CWE-400・CWE-502 を付けています。

ただし、OWASP の分類では、どちらも同じ A03 に入ります。A03 の例には、Shai-Hulud と Log4Shell の両方が挙げられています。OWASP は、部品はアプリと同じ権限で動くので、どの部品の欠陥も重く、欠陥はうっかり(コードの誤り)のことも、わざと(部品の裏口)のこともある、と説明しています。「同じ項目の中に、起き方の違う 2 種類がある」と考えると、両方の説明が両立します。

部品の穴の最近の例としては、2026年10月の React・Next.js の脆弱性があります。くわしくはReact・Next.js の脆弱性の記事を見てください。

防ぐには?自分のプロジェクトで何を見るか(2026年10月時点)

型ごとに「見る所」を並べると、次のようになります。手順は、リンク先の記事に任せます。

型見る所手順の記事
1 資格情報疑わしいときは資格情報を取り替える。開発者のアカウントにフィッシングに強い多要素認証を使うnpm・yarn・pnpm
2 タグ完全な SHA で固定する(2026年10月時点で公開プレビューの lockfile も、GitHub は勧めている)GitHub Actions
3 スクリプトインストール時のスクリプトを止める。公開から日が浅い版を待つnpm・yarn・pnpm
4 CI の設定pull_request_target で信用できないコードを checkout しない。権限を絞るだけではキャッシュは守れない(TanStack)GitHub Actions
5 配布物依存の版を意図して選ぶ。使っている部品を把握するnpm・yarn・pnpm

使う側(npm)

  • lock ファイル。 package.json は「許す版の範囲」、lock ファイル(npm なら package-lock.json)は「そのとき決まった、入れる版」です。lock ファイルを Git に入れ、次も同じ木(依存の一覧)を作れるようにします。CISA は Shai-Hulud のとき、当たったかを lock ファイル(package-lock.json・yarn.lock)で、入れ子になった依存も含めて確かめるよう勧めました。CI では npm ci を使うと、lock ファイルどおりに入れ、package.json と合わなければ、lock を書き換えずにエラーで止まります
  • 版を意図して選ぶ。 CISA は axios と Shai-Hulud の 2 回とも、「知られた安全な版に固定する」を勧めました。OWASP も、依存の版は意図して選び、要るときだけ上げるよう書いています
  • 公開から日が浅い版を待つ。 npm は min-release-age(日数。既定は無効。11.10.0 から)、pnpm は minimumReleaseAge(分。v11 から既定 1440 分。ただし自分で書かないと「ゆるい」扱いで、条件に合う版が無いときは待たずに入れます)、Yarn は npmMinimalAgeGate(4.15.0 から既定 "1d")です。CISA は axios のとき min-release-age=7 を勧めました。ただし、待ちのせいで npm audit fix が直った版を入れられないと、古い版のまま、0 以外の終了コードで終わります
  • インストール時のスクリプトを止める。 npm の ignore-scripts があります。npm 12(2026年7月8日)からは、依存のライフサイクルスクリプトが既定で止まります(許すものは allowScripts、npm install-scripts approve で決めます)。pnpm は v10 から、Yarn 4 は 4.14.0 から、既定で走らせません
  • 当たった版を入れたら。 入れたマシンから届く資格情報を取り替えます。CISA は、VCS(Git など)のトークン・CI/CD の秘密・クラウドの鍵・npm のトークン・SSH の鍵を例に挙げています。TanStack の事後報告も、同じ種類の資格情報の取り替えを強く勧めています

使う側(GitHub Actions)

  • 完全な SHA で固定する。 SHA は、コミットを 1 つに決める 40 桁の文字列です。ただし、Trivy の件のとおり、SHA で固定しても、中で呼ばれるものまで固定されるとは限りません。SHA で固定した action には Dependabot(依存の更新を知らせる GitHub の機能)の脆弱性の通知が出ない、という点も、知っておくことです。リポジトリや organization の設定で、SHA の固定を必須にもできます(2025年8月15日から)。GitHub の公式文書は、これとは別に、workflow の依存を lockfile で固定することを、いちばんの手当てとしています。ただし、この lockfile は2026年10月時点で公開プレビューで(2026年10月14日の発表。対象は GitHub Enterprise Cloud・Team・Free のプラン)、変わることがあります。依存の依存まで、使う action の正確なコミットを記録し、実行のときに取り先のリポジトリを確かめます(reusable workflow の依存は対象外で、それを定義したリポジトリの lockfile が受け持ちます)。固定しても、その依存が安全かは決まらないので、固定する前に依存を見ます(lockfile の公式文書・発表)
  • pull_request_target を避ける。 要らなければ使いません。使うなら、信用できない pull request のコードを checkout しません

公開する側

  • 変えられないリリース。 GitHub の immutable releases は、公開したあと、リリースのファイルと Git のタグを変えられなくします。タグはリリースがある限り動かせず、消せません。Trivy では、この設定で守られた版がありました
  • trusted publishing。 CI から OIDC で公開し、長く使える npm のトークンを要らなくします。npm CLI 11.5.1 以上・Node 22.14.0 以上が必要で、GitHub Actions(GitHub のランナー)・GitLab.com・CircleCI に対応しています。セルフホストのランナーは未対応です。GitHub Actions か GitLab CI/CD から、公開のリポジトリで公開のパッケージを出すときは、provenance が自動で付きます(CircleCI と、非公開のリポジトリからでは付きません)
  • 設定したらトークンでの公開を止める。 npm は、trusted publisher を設定したら、トークンでの公開を止める("Require two-factor authentication and disallow tokens")ことを強く勧めています。さらに強くするなら、「stage だけ」の権限にして、CI からの公開を、メンテナーが 2 要素認証で承認するまで公にならないようにできます
  • それでも足りないこと。 型 4 のとおり、trusted publishing と provenance だけでは、悪い版が出ないとは言えません。CI の設定の穴を塞ぐことと、組み合わせます
  • 組織としては。 OWASP は、SBOM を作って管理すること、依存の依存まで追うこと、使わない依存を消すこと、更新を全部のシステムに一度に入れないこと、CI/CD や IDE などの開発の道具も定期的に更新することを挙げています

手元で確かめると?小さなプロジェクトで流した出力

「自分のプロジェクトで何を見るか」の一部を、小さなプロジェクトで流しました。環境は macOS 14.4.1、Node 21.7.1・npm 10.5.0 です。npm 12.2.0 は、Node 24.21.0 の上で npx -y npm@12.2.0 として動かしました。部品は minimist@1.2.5(脆弱性が知られている古い版)と esbuild@0.25.0(postinstall を持つ版)の 2 つだけです。どちらも悪意のあるパッケージではありません。npm 10.5.0 では、スクリプトを走らせないよう --ignore-scripts を付けて入れました。悪い版を取りに行くことはしていません。

npm init -y
npm install --ignore-scripts --save-exact minimist@1.2.5 esbuild@0.25.0
added 3 packages, and audited 4 packages in 469ms

1 critical severity vulnerability
…

npm ls:入っているものを見る

npm ls は、入っているパッケージの版を木の形で出します。--all を付けると、依存の依存まで見えます。なぜ入っているかを下から見るには npm explain です。

npm ls
proj@1.0.0 /…/proj
+-- esbuild@0.25.0
`-- minimist@1.2.5

直接入れたのは 2 つですが、npm ls --all で見ると、esbuild の下に @esbuild/darwin-arm64 がもう 1 つ入っていて、「added 3 packages」と合います。

npm query:インストール時のスクリプトを持つ部品を探す

npm の公式の文書にある書き方で、postinstall を持つ部品を探せます。公式の例は見つけたものを uninstall まで流しますが、探すところまでで足ります。

npm query ":attr(scripts, [postinstall])"

出た JSON から、名前・版・postinstall だけを取り出すと、1 件でした。

esbuild@0.25.0  postinstall: node install.js

[install] と [preinstall] で同じように探すと、どちらも 0 件でした。

npm audit:知られた脆弱性を見る

npm audit は、プロジェクトの依存の一覧を registry に送り、知られた脆弱性の報告をもらうコマンドです。見つかると 0 以外の終了コードで終わります。

$ npm audit
# npm audit report

minimist  1.0.0 - 1.2.5
Severity: critical
Prototype Pollution in minimist - https://github.com/advisories/GHSA-xvch-5gv4-984h
…(途中を省略)
1 critical severity vulnerability
…
(終了コード 1)

postinstall を持つ esbuild は、npm audit には出ませんでした。 postinstall は脆弱性ではないからです。スクリプトを持つかどうかは、さきほどの npm query で見ます。また、npm audit は全部を出すわけではありません。2026年10月19日の時点で、React・Next.js の 5 件の脆弱性は、GitHub の Advisory Database(npm audit が引く一覧)にまだ無く、npm audit に出ませんでした(sharp の件は出ました)。くわしくはReact・Next.js の脆弱性の記事にあります。

npm audit signatures は、入れたパッケージの registry の署名を確かめ、provenance の証明も確かめます。

$ npm audit signatures
audited 3 packages in 0s

3 packages have verified registry signatures

npm ci:lock ファイルどおりに入れる

package.json だけ minimist を "1.2.8" に書き換え(lock ファイルは 1.2.5 のまま)て npm ci を流すと、npm 10.5.0 では、エラーで止まりました(終了コード 1)。確かめたあと、package.json は元に戻しています。

npm ERR! code EUSAGE
npm ERR! `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing.
npm ERR! Invalid: lock file's minimist@1.2.5 does not satisfy minimist@1.2.8
…

npm 12.2.0:インストール時のスクリプトが止まる

同じ package.json と lock ファイルで、npm 12.2.0 の npm ci を流しました。--ignore-scripts を付けなくても、esbuild の postinstall は止まりました。

…
npm warn install-scripts 1 package had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts   esbuild@0.25.0 (postinstall: node install.js)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.

止めたスクリプトの一覧は npm install-scripts ls で出ます。許すなら npm install-scripts approve <pkg> ですが、承認は流していません。npm 12 のスクリプトの止まり方は、先ほどの npm query の結果と同じ 1 件でした。

よくある質問

npm 12 にすれば、TanStack の件は防げましたか?

当事者は書いていません。npm 12 は2026年7月8日に出たもので、TanStack の件(2026年5月)より後です。この記事では「防げた」とは書きません。npm 12 の既定でインストール時のスクリプトが止まることは、手元で確かめましたが、TanStack の件との関係は、確かめられた文書がありません。

npm audit で、乗っ取られた版は見つかりますか?

この記事では確かめていません。悪い版を取りに行かない方針のため、試していません。確かめられたのは、npm audit は知られた脆弱性の報告をもらうコマンドであることと、全部を出すわけではないこと(React・Next.js の 5 件が出なかった例)までです。

自分のアプリで確かめること(チェックリスト)
  • lock ファイル(npm なら package-lock.json)を Git に入れ、CI では npm ci で入れているか。依存の版を意図して選び、要るときだけ上げているか(→「使う側(npm)」)
  • インストール時のスクリプトを止めているか(npm の ignore-scripts。npm 12 からは、依存のライフサイクルスクリプトが既定で止まる)(→「使う側(npm)」)
  • 公開から日が浅い版を待つ設定を、使っているツールで確かめたか(npm の min-release-age は 11.10.0 から、既定は無効)(→「使う側(npm)」)
  • 他人の action を、動かせるタグではなく、完全な SHA で固定しているか。固定した action の中で呼ばれるものまで固定されているか(→「使う側(GitHub Actions)」)
  • pull_request_target を、要らなければ使わず、使うなら信用できない pull request のコードを checkout していないか(→「使う側(GitHub Actions)」)
  • 公開する側なら、変えられないリリースや trusted publishing を使い、trusted publisher を設定したらトークンでの公開を止めているか。それだけで悪い版が出ないとは考えず、CI の設定の穴も塞いでいるか(→「公開する側」)
  • 当たった版を入れてしまったとき、入れたマシンから届く資格情報(Git のトークン・CI/CD の秘密・クラウドの鍵・npm のトークン・SSH の鍵)を取り替えられるか(→「使う側(npm)」)
  • 開発者のアカウントに、フィッシングに強い多要素認証を使っているか(→「防ぐには?自分のプロジェクトで何を見るか(2026年10月時点)」)

まとめ

  • ソフトウェアのサプライチェーン攻撃は、作り手の環境や配る道筋に悪いコードを入れ、そのソフトを使う人すべてに及ぶ攻撃。IPA 10大脅威の 2 位は、取引先を通る話も含む別の範囲で、この記事が扱うのは「ソフトウェアの繋がり」の側だけ
  • 乗っ取りの入口は、この記事では 5 つの型に分けた。盗まれた資格情報(axios・Shai-Hulud・Trivy)、タグの書き換え(tj-actions・Trivy)、インストール時のスクリプト(Shai-Hulud・TanStack)、CI の設定の穴(TanStack)、配布物・ビルドの汚染(xz utils)
  • TanStack の件は、公開が正規の trusted publisher を通っていた。trusted publishing や provenance だけでは、悪い版が出ないとは言えない。公開 1 回ごとのレビューが無いこと、provenance は悪いコードが無いことまでは保証しないことを、一緒に覚えておく
  • SHA で固定していても、中で呼ばれるものまで固定されていなければ、当たることがある(Trivy)
  • Log4Shell は、乗っ取りではなく、部品の穴。CVE の記録でも、乗っ取りの 3 件は CWE-506、Log4Shell は CWE-506 ではなく CWE-917 などが付いている(付けた機関は件によって別)。OWASP の分類では、どちらも A03
  • 見る所は、lock ファイルと npm ci、版の選び方、日が浅い版を待つ、インストール時のスクリプト、workflow の依存の固定(lockfile か SHA)、pull_request_target、資格情報の取り替え。手順はnpm・yarn・pnpm の記事とGitHub Actions の記事へ
  • npm audit は、知られた脆弱性を見るもの。全部を出すわけではなく、インストール時のスクリプトの有無も出さない

Web 開発で点検することの全体は、Web 開発のセキュリティの基本にまとめています。

参考資料

この記事の内容は、2026年10月20日に開いた文書をもとにしています。ベンダー(セキュリティ会社)の調査記事は使っていません。npm や GitHub の仕様は変わるので、使う前に最新の文書を確かめてください。

※この記事は、公式の資料をもとに AI(Claude)で下書きし、2026年10月20日時点の公式の資料と照らして確かめてから公開しています。誤りに気づいたらお問い合わせからお知らせください。

PR
PR
タイトルとURLをコピーしました