ディスカッション (11件)
人気ライブラリのTanStackで発生したnpmサプライチェーン攻撃に関する事後検証(ポストモーテム)が公開されました。詳細な調査経緯や被害状況については、以下のGitHubイシューを参照してください。 https://github.com/TanStack/router/issues/7383
npm環境をセキュアにするようリマインド。https://gajus.com/blog/3-pnpm-settings-to-protect-yourself-from-supply-chain-attacks ちょっとした設定で、大きなトラブルを回避できるぞ。
残念だけど、これはTrusted Publishing(TP)単体ではCIからの安全な公開にはまだ不十分だという証拠だと思う。CIパイプラインの内部に侵入した攻撃者や、盗まれたリポジトリの管理者権限を持つ攻撃者は、簡単に公開できてしまうからね。新しい話ではないし、TP自体がこれを防ぐためのものではないけど、ローカルでの2FA付き公開からTPへ移行すると、CIが侵害された時にこの手の攻撃経路ができてしまう。(追記:「まだ安全ではない」から「単体では不十分」に書き換えた。伝えたいのはそこだから)
Trusted Publishingやパイプライン公開に移行すると、ローカルで作業する際に通常npm publishを制御していた第2要素が外れてしまう。
今回の件は、まだ詳細が明らかになりつつある段階だけど、攻撃者がCI/CDパイプラインを侵害し、npm publishに第2要素がないためにOIDCトークンを盗んで公開を完了させた、ということらしい。
面白い(というか無関係かもしれないが)のは、公開ジョブ自体は失敗していること。つまり、悪意のあるコミットに含まれていたペイロードには、ワークフローから取得したOIDCトークンを使って自分自身を公開できるスクリプトが含まれていたはずだ。
個人的に欲しいのは、Githubに依存した長期間有効なトークンレスのTrusted Publisherモデルを使いつつも、CI公開時にはGithub外での第2要素を必須にすること。つまり、誰かが2FAを使ってnpm側でアーティファクトを公開状態に昇格させるという「ステージング公開」だ。
そうじゃないと、Githubの信頼モデル内だけで公開が完結してしまう場合、リポジトリの管理トークンを乗っ取ったり、パイプラインに悪意あるコードを忍び込ませたりできる人間なら誰でも簡単に公開できてしまう。Github外の真の第2要素があれば、リポジトリへのダメージや悪意あるコードの混入は防げなくても、少なくともレジストリに対しては第2要素なしに公開することはできなくなるはずだ。
postinstallスクリプトは致命的だよ。
みんなpnpmを使うべきだ。
フォーク(!)にプッシュされた「孤立した」コミットが(npmクライアントにおいて)これを引き起こせるなんて信じられない。個人的にはGitHubにかなりの責任があると思う。悪意のあるフォークのコミットが、GitHubの共有オブジェクトストレージを経由して、正規のリポジトリと見分けがつかないURIから到達可能になっているなんて、全く正気の沙汰じゃない。
トークンを無効化する際は注意して。このペイロードは ~/.local/bin/gh-token-monitor.sh にデッドマンズ・スイッチ(死んだ時に作動する仕掛け)を仕込み、systemdユーザーサービス(Linux)またはLaunchAgent com.user.gh-token-monitor(macOS)として実行されるようだ。60秒ごとに盗まれたトークンを使って api.github.com/user をポーリングし、トークンが無効化される(HTTP 40x)と、rm -rf ~/. を実行する仕組みらしい。
https://github.com/TanStack/router/issues/7383#issuecomment-4425225340
もうみんな各プロジェクトを個別のVMで実行すべき段階に来ていると思う。
最近のLPE(ローカル特権昇格)脆弱性を考えると、Dockerでは100%不十分だし。
そもそもコンテナはセキュリティ境界として設計されたものじゃないからね。
このマルウェアは「prepare」フックを使ってbunでペイロードを実行してる。皮肉なことに、bun自体はこの攻撃には耐性があるんだけどね。2026年になっても依存関係のライフサイクルスクリプトをデフォルトで有効にするなんて、単なる手抜きだよ。
@mistralai/mistralai npmパッケージもこのワームの一部として侵害されていたみたいだ。
https://github.com/mistralai/client-ts/issues/217
現在はnpmレジストリから削除されている。
https://tanstack.com/blog/npm-supply-chain-compromise-postmortem
我々(TanStack)から今回の件についての事後分析(ポストモーテム)を公開したよ。
うわぁ、また巨大なパッケージがやられたのか。AxiosやLiteLLMが被害に遭った後に投稿したPSA[0][1]を再掲しておくよ。ライフサイクルスクリプトに関する部分も重要だ:
PSA: npm/bun/pnpm/uvはすべて、パッケージの「最小リリース経過期間」を設定できる。
あと、俺は ~/.npmrc に ignore-scripts=true を設定してる。分析を見る限り、これだけでも脆弱性を防げたはずだ。bunとpnpmはデフォルトでライフサイクルスクリプトを実行しないしね。
最小リリース経過期間を7日に設定するためのグローバル設定は以下の通り:
~/.config/uv/uv.toml
exclude-newer = "7 days"
~/.npmrc
min-release-age=7 # 日
ignore-scripts=true
~/Library/Preferences/pnpm/rc
minimum-release-age=10080 # 分
~/.bunfig.toml
[install]
minimumReleaseAge = 604800 # 秒
もしグローバル設定を上書きしたい場合は、CLIフラグで指定できる:
npm install <package> --min-release-age 0
pnpm add <package> --minimum-release-age 0
uv add <package> --exclude-newer "0 days"
bun add <package> --minimum-release-age 0
一つ付け加えておくと、依存関係の導入を遅らせることで脆弱性の発見が遅れるとか、フリーライダー(タダ乗り)のような行為ではないかという懸念があるようだ。俺はそうは思わない。これによってトレードオフしているのは「時間的選好」だ。誰かが先に検証してくれるのを待つのは悪いことじゃない。
0: https://news.ycombinator.com/item?id=47582220
1: https://news.ycombinator.com/item?id=47513932