Skip to content

npmの公開に人の承認を挟む流れが強まっている

WordPressのブロックテーマやプラグインを作っていると、npmを使わない日はほとんどありません。ビルド用のツール一式も、CSSの処理も、小さな便利ライブラリも、たいていnpm経由で入ってきます。そのnpmで、9月に入ってから公開の手順まわりの変更が立て続けに発表されました。一つひとつは地味な更新ですが、並べてみると「パッケージを公開する最後の一押しは人間がやる」という方向がはっきり見えてきます。

今回は、GitHubの変更履歴(Changelog)に9月に載った三つの更新と、6月に予告されたnpm v12の既定値の変更、そしてその背景にある8月のワーム被害をつなげて、制作の現場から見た意味を考えてみます。

8月に起きたことを振り返る

話の出発点は、8月4日に起きたnpmパッケージの大規模な乗っ取りです。Datadog Security Labsの分析によると、キャッシュ用ライブラリとして広く使われているkeyvのGitHubリポジトリに不正なコミットが入り、そこから公開された版に悪意あるコードが仕込まれました。同じ手口はcacheable系のパッケージ群やectoにも広がり、flat-cacheやfile-entry-cacheといった、名前を見れば依存関係の奥で見覚えのあるパッケージも含まれていました。コミュニティではChainDropと呼ばれています。

仕組みとしては、パッケージのインストール時に自動で走るpreinstallスクリプトから読み込み役のファイルを起動し、そこから本体を動かすというものです。本体は開発者の端末やCIの環境から、GitHubやnpmのトークン、クラウドの認証情報、環境変数などを集めて外部へ送り出します。さらに、盗んだnpmトークンのうち二要素認証を迂回できる設定のものを見つけると、そのトークンで書き込める別のパッケージにも同じ仕掛けを入れて勝手に新しい版を公開する、という自己増殖の機能まで備えていました。

見落とせないのは、keyvの問題の版が、GitHub Actionsのワークフローから正規の手順で公開され、正しい来歴証明(provenance)まで付いていたという点です。Datadogは、来歴証明は「どこでどう作られたか」を示す証拠であって、安全かどうかの判定ではないと指摘しています。ワークフローそのものが乗っ取られていれば、証明は悪意あるコードの出どころを忠実に記録してしまうわけです。

ステージ公開という考え方

こうした流れを受けて、npmが力を入れているのがステージ公開(staged publishing)です。これは、新しい版をいきなりレジストリに出すのではなく、いったん「公開待ち」の状態に置き、メンテナーが二要素認証を通したうえで承認して初めて公開される、という手順です。

9月3日の更新では、この仕組みまわりに三つの変更が一般提供になりました。一つ目は、トークンを使わずにCIから公開する信頼済み公開(trusted publishing)の設定を、一つのパッケージに複数持てるようになったこと。安定版、プレリリース版、検証用といったワークフローを分けて運用できるようになり、これまでOIDCでまかなえない経路のために長期間有効なトークンを残しておく、といった回避策が要らなくなります。

二つ目は、公開待ちのパッケージはマルウェアの検査が終わるまで承認ボタンが押せなくなったこと。三つ目は、npmjs.comの版一覧で、それぞれの版が承認されたのか、却下されたのか、まだ待ち状態なのかという履歴がメンテナーから見えるようになったことです。

興味深いのは、信頼済み公開の設定は既定で「ステージまで」しかできず、直接の公開は設定ごとに明示的に有効にしないと使えない、という点です。GitHubは設定をステージ専用のままにしておくことを勧めています。ワークフローが乗っ取られても、人の承認がなければレジストリまで届かない。8月の件で破られた部分を、ちょうど塞ぐ形になっています。

トークンにも「ステージまで」の権限ができた

9月18日には、細かく権限を絞れるアクセストークン(granular access token)に、読み書きのうち「ステージのみ」という選択肢が加わりました。このトークンを使う自動化の処理は、npm stage publishで版を公開待ちに出すことはできますが、npm publishで直接公開しようとすると拒否されます。二要素認証の迂回を許可する設定にしていても同じです。

背景には、npmが2027年1月をめどに、二要素認証を迂回するトークンによる直接公開を廃止する予定だという事情があります。信頼済み公開にすぐ移れない現場向けの、移行の足がかりという位置づけです。ただし、ステージ専用トークンも配布タグの付け替えや版の非推奨化といった書き込み権限は残っているため、ほかの書き込み用トークンと同じように慎重に扱うよう注意書きがあります。利用にはnpm CLI 11.15.0以降、Node.js 22.14.0以降が必要とされています。

8月のワームが増殖に使ったのは、まさに二要素認証を迂回できる書き込み用のトークンでした。ステージ専用に切り替わっていれば、盗まれても勝手に新しい版を世に出すことはできません。ここでも、狙われた経路に対してピンポイントで手が打たれているのがわかります。

アカウントを取り戻したあとの猶予期間

9月9日の更新はもう少し地味で、リカバリーコードでサインインしたアカウントに、72時間の保留期間を設けるというものです。これまでは影響の大きいアカウントだけに適用されていた保護が、すべてのnpmアカウントに広がりました。

保留中は、サインインやパッケージの閲覧、インストールはできますが、公開やアクセストークンの作成といった影響の大きい操作が止まります。期間が過ぎれば自動で解除され、問い合わせなどは必要ありません。リカバリーコードが盗まれてアカウントを乗っ取られた場合に、すぐに悪意ある版を出されるのを遅らせるための仕組みです。自分で使った覚えがないのに公開できなくなったら、すぐにnpmのサポートに連絡してほしいとされています。

インストールする側の既定値も変わる

ここまでは公開する側の話でしたが、使う側にも大きな変更が予告されています。6月に発表されたnpm v12の破壊的変更では、npm installの挙動のうち、これまで自動で動いていたものを明示的に許可する方式に切り替えるとされています。

中心になるのは、依存パッケージのpreinstall、install、postinstallといったスクリプトを、既定では実行しなくなるという変更です。ネイティブ拡張のビルドも対象に含まれます。どのパッケージのスクリプトが止まるかはnpm approve-scriptsで一覧でき、信頼するものだけを許可すると、その許可リストがpackage.jsonに書き込まれます。あわせて、Gitリポジトリやhttpsのtarballといった外部の場所から依存を取ってくる動作も、既定では許可しない方向です。これらはnpm 11.16.0以降で警告として先に確認できます。

8月のワームが最初に動き出したきっかけはpreinstallスクリプトでした。インストールしただけで任意のコードが走るという、長年の前提そのものに手が入るわけで、影響は小さくありません。

制作会社の現場で見直しておきたいこと

npmにパッケージを公開していない制作会社でも、使う側としての備えは必要です。まず、案件ごとのリポジトリでnpmのバージョンを上げ、どのパッケージがインストール時にスクリプトを実行しているのかを一度洗い出しておくと、v12への移行で慌てずに済みます。古い案件ほど、ビルドの途中でネイティブ拡張を組み立てるパッケージが紛れていることがあり、許可リストの作成に意外と手間がかかるかもしれません。

次に、CIに置いているトークンの棚卸しです。今回の分析では、盗まれた情報の中心がCIの環境変数や認証情報でした。保守契約で複数のサイトを預かっている場合、デプロイ用の鍵やサーバーの認証情報がCIにまとまって置かれていることも多いはずです。npmのトークンに限らず、権限が広すぎないか、使っていないものが残っていないかを確かめておく価値はあります。

自社でプラグインやライブラリを公開しているなら、信頼済み公開とステージ公開への移行を検討するよい時期です。承認の手間は増えますが、少人数の現場ほど「誰かのアカウントが一つ破られたら終わり」という状態になりやすく、人の目を一段挟む意味は大きいと感じます。

私たちRESONIXでも、テーマやプラグインの開発にnpmを日常的に使っています。便利な仕組みの上に乗っている以上、その仕組みが変わる方向は追いかけておきたいところです。今回の一連の変更は、自動化を減らすのではなく、自動化の最後に人の判断を戻すという整理の仕方で、ほかのツールにも広がっていきそうな考え方だと思います。

[1994-2002]
ITベンチャーの幹部として、8年間で数名の企業を500名以上の企業に成長させることに貢献。95年より独学でwebデザインを学ぶ。

[2002-2023]
米国法人のwebデザイン会社のCEOを務め数々の賞を受賞。

[2023〜]
AI事業開始に伴い、つくば市を拠点として株式会社RESONIXを起業。