npm install すると、AWS / GCP / Kubernetes / Vault / GitHub / SSH などの認証情報を盗む動きがあったTanStack が公開した postmortem は、かなり生々しいです。
要するに、GitHub の pull request を使った開発フローと、GitHub Actions のキャッシュ、そして npm の trusted publishing が、攻撃者にとって都合よくつながってしまった、という話です。
2026-05-11 の 19:20〜19:26 UTC の間に、攻撃者は 42 個の npm パッケージに対して合計 84 個の悪意あるバージョンを公開しました。
しかも厄介なのは、これが単なる「npm アカウント乗っ取り」ではなく、GitHub Actions の実行環境上で OIDC token を抜き取り、その権限で npm に直接 publish した形だということです。
ここ、かなり面白くて、同時に背筋が寒いところです。
「npm の秘密鍵が漏れたわけではない」のに、結果としては正規の公開操作に見える形で悪性パッケージが流通した。これ、サプライチェーン攻撃のいやらしさが全部詰まっています。
影響を受けたバージョンを npm install、pnpm install、yarn install すると、以下のような動きが走りました。
~/.npmrc、GitHub token、SSH private key などを収集するこの「自分を増やす」動きがかなり悪質です。
単に情報を抜くだけではなく、次の被害者を増やすための足場まで作りにいっている。個人的には、ここが一番イヤなポイントだと思います。被害が“感染”っぽく広がるからです。
攻撃は、ざっくり3段階です。
GitHub Actions の pull_request_target は、PR の変更内容に対して、ベースリポジトリ側の権限で動く仕組みです。
本来は、ラベル付けやコメントなどの「安全な作業」に向いています。
ところが今回、TanStack の bundle-size.yml はこの pull_request_target 上で、PR のマージ後コードを checkout して build を実行していました。
つまり、外部から来たコードを、ベースリポジトリの文脈で実行してしまったわけです。
ここで大事なのは、pull_request_target 自体が悪いのではなく、何を実行するかです。
コメントだけならまだしも、build や install を走らせると、急に話が危なくなる。GitHub Actions は便利ですが、便利さの裏に「権限の境界」があるんですよね。
攻撃者は、PR 内で悪意あるコードを実行し、pnpm store に細工しました。
そのあと actions/cache がその汚染済みキャッシュを保存してしまい、後続の main ブランチの workflow がそれを復元してしまった、という流れです。
GitHub Actions の cache は、ざっくり言うと「ビルド結果や依存関係を保存して次回を速くする仕組み」です。
でもこれは裏を返すと、一度混ざった毒を、次の実行に持ち越せるということでもあります。
ここは本当に教訓的です。
キャッシュって普通は“善意の時短装置”なんですが、信頼境界をまたぐと毒の保冷庫になるんですよね。かなり皮肉が効いています。
最後の決め手がこれです。
release workflow には id-token: write が設定されていて、これは npm の OIDC trusted publishing に必要です。
OIDC は、短命のトークンで安全に外部サービスへ認証する仕組みで、セキュリティ的にはかなり良い考え方です。
ただし、攻撃者が runner 上でコードを実行できる状態だと、そのトークンをメモリから抜き取られる可能性がある。
今回の悪性コードは、GitHub Actions runner のプロセスを探して、/proc を読みにいき、メモリから OIDC token を取り出して、npm registry に直接 POSTしました。
つまり、workflow の「Publish Packages」ステップを通らなくても、publish 権限そのものを奪ってしまったわけです。
ここは正直、かなり巧妙です。
「ワークフローの中の publish step を守れば安心」と思いがちですが、実際にはrunner 上で実行できるコードがある時点で、認証トークンの扱い全体が危うい。クラウド時代のセキュリティって、本当に“実行環境そのもの”が攻撃対象になるんだな、と感じます。
TanStack の説明では、この攻撃は 3つの問題が鎖のようにつながって成立したと整理されています。
pull_request_target により、PR由来のコードが base repo 側の文脈で走ったそれぞれ単体なら、すぐに大事故にならないかもしれません。
でも、境界をまたぐたびに信頼が少しずつ崩れると、最後には「正規の publish に見える malicious publish」が成立してしまう。
このタイプの攻撃は、見た目が地味なのに被害が派手で、かなり厄介です。
検知は、外部の研究者による発見が先でした。
ashishkurmi が公開 issue に詳しい分析を投稿し、かなり早い段階で広く共有されました。TanStack 側もすぐに動き、npm security への連絡、該当パッケージの deprecate、GitHub の権限整理、キャッシュの削除、ワークフローの修正などを進めています。
この「外部研究者が先に見つけた」という事実は、少し複雑です。
もちろん事故は起きない方がいい。でも現実には、オープンソースの巨大な供給網では、コミュニティの目が最後の防波堤になることがある。これは健全さでもあり、しんどさでもあると思います。
TanStack は、影響を受けたバージョンをインストールした可能性がある人に対して、インストールホストから到達可能な認証情報をローテーションするよう強く勧めています。
具体的には次のようなものです。
ここで大事なのは、「npm を入れ直せば終わり」ではないことです。
もし悪性パッケージがインストール時に認証情報を抜いていたら、そのマシンから使える秘密情報は全部見直し対象です。
これは面倒ですが、サプライチェーン攻撃の後処理としては避けられません。
この件で一番学びが大きいのは、**“安全そうに見える便利機能”が、つながると危険になる**ということだと思います。
pull_request_target は便利でも、これらはそれぞれ単体ではなく、組み合わせたときの信頼境界を見ないといけない。
セキュリティって、結局「この機能は危険か?」ではなく、**“どこまで信用していい前提で動いているか”**の設計なんですよね。
TanStack の postmortem は、そのことをすごくわかりやすく示していると思います。
しかもこれは TanStack だけの話ではなく、GitHub Actions を使う多くのプロジェクトにそのまま刺さる話です。
便利なCIほど、雑に組むと一気に危険になる。そこは本当に気をつけないといけません。
今回の事件は、単なる「パッケージが汚染された」では終わりません。
PR、CI cache、OIDC、npm publish が全部つながって、サプライチェーン全体が攻撃の入り口になったのが本質です。
しかも怖いのは、攻撃が派手なゼロデイではなく、既知のパターンや既知の手口の組み合わせで成立していること。
つまり、「珍しい脆弱性がなくても、設計の継ぎ目を突けばここまで行ける」ということです。これはかなり現実的で、だからこそ学ぶ価値が大きい事件だと思います。
参考: Postmortem: TanStack npm supply-chain compromise | TanStack Blog