npmの段階公開 — CIだけでリリースできる状態を止める | GH Media
URLがコピーされました

npmの段階公開 — CIだけでリリースできる状態を止める

URLがコピーされました
npmの段階公開 — CIだけでリリースできる状態を止める

自社の共通UIコンポーネントやAPIクライアントを npm パッケージとして配っている。あるいは、委託先が作ったSDKを社内のプロジェクトが軒並み参照している。この構成自体は珍しくありません。

問題は、その公開が CI に置いたトークン1本で完結している ことです。タグを打てばワークフローが走り、ビルドが通れば公開される。人は誰も間に入りません。効率としては正しい設計ですが、裏を返せば、そのトークンを手に入れた誰かも同じことができます。しかも新しいバージョンは、公開された瞬間から世界中の npm install に配られます。

2026年に相次いだサプライチェーン攻撃の多くは、脆弱性を突いたものではありませんでした。CI/CD から盗んだ公開トークンを使い、正規の手順で汚染版を公開するという形です。ビルドは通っていて、署名も正規で、公開者も正規のアカウント。検知が難しいのは、どこも異常ではないからです。

最後の一歩だけを、人に戻す

npm はこれに対して、公開の直前に人間の承認を挟む仕組みを追加しました。段階公開(staged publishing)で、2026年5月22日から全パッケージで利用できます。

動きはこうです。npm publish の代わりに npm stage publish を実行すると、パッケージはレジストリに載らず、ステージングのキューに入ります。この時点では誰もインストールできません。そのあと、メンテナが2要素認証を通したうえで承認して、初めて公開されます。

操作は次のサブコマンドで完結します。

npm stage publish              # ステージングキューに積む(2FA不要・CIから実行できる)
npm stage list                 # 承認待ちの一覧を見る
npm stage view <stage-id>      # 中身(tarball)を確認する
npm stage approve <stage-id>   # 2FA を通して公開する
npm stage reject <stage-id>    # 破棄する

**npm stage publish は、トークンの種類にかかわらず2FAを求めません。**これが設計上の勘所です。CI は今までどおり自動でビルドして積むところまでを担当し、世に出す判断だけが人の手に残ります。CI を弱くすることなく、盗まれたトークンでできることの上限を「キューに積むこと」まで下げられます。

CIが公開まで完結する従来のフローと、ステージングキューを挟んで人が2FAで承認するフローの比較図

推奨される構成は「CIは積むだけ」

GitHub 側が示している組み合わせは、OIDC を使った信頼できる公開(trusted publishing)と段階公開の併用です。ワークフローの権限を stage-only に設定すると、npm stage publish は通り、npm publish は拒否されます。

この設定が入って初めて、抜け道がなくなります。段階公開を導入しても、従来の npm publish が使えるまま残っていれば、攻撃者はそちらを使うだけです。承認ゲートは、迂回路を塞いで初めてゲートになります。

同時期に、インストールする側の制御(--allow-* 系のオプション)も追加されています。公開する側と使う側の両方に手が入った形なので、自社がどちら側なのかで見るべき機能が変わります。パッケージを配っていない組織にとっては、後者のほうが直接効きます。

導入前に確認しておくこと

要件は、npm CLI 11.15.0 以降と Node.js 22.14.0 以降です。CI のランナーが古い Node のまま固定されている場合、ここで引っかかります。リリース用ワークフローのバージョン指定を先に確認してください。

いくつか制約もあります。

新規パッケージは段階公開できません。レジストリに既に存在するパッケージが対象です。最初の1回は従来どおり公開する必要があります。

ステージング時に付けたタグは、あとから変更できません。latest で積んだものを next に変えたい場合は、いったん npm stage reject で破棄してから積み直します。タグの付け間違いが起きやすいリリース手順なら、ここは事前に整理しておくほうが混乱が少なくなります。

リリースツールとの相性が出ます。changesets のような自動リリースツールを使っている場合、npm publish を直接呼ぶ実装になっていると段階公開の経路に乗りません。対応状況を確認してから移行時期を決めてください。

運用で形骸化させないために

承認ゲートは、入れた翌月から形骸化が始まります。防ぐ側の手当てを最初に決めておきます。

承認者を1人にしないでください。リリースが承認者の在席に依存すると、不在の日に緊急パッチが出せません。「承認者が休みなので今回は直接公開した」が1回でも通ると、その経路が常用されます。

承認時に何を見るかを決めておいてください。npm stage view で中身を確認できる仕組みがあっても、見る基準がなければクリックするだけの作業になります。差分のファイル数、想定していないファイルの混入、依存関係の追加、postinstall スクリプトの有無。この程度でも、決めてあるかどうかで意味が変わります。インストール時に走るスクリプトが何をしうるかはnpm install で任意コードが走るという前提で扱っています。

承認までの待ち時間を、リリース計画に織り込んでください。「即座に出せる」前提でスケジュールを組んだままだと、承認が律速になった瞬間にゲートを外す圧力がかかります。

使う側にとって何が変わるか

自社がパッケージを配っていない場合、この機能は直接は関係ありません。ただし、依存している主要パッケージが段階公開を採用しているかどうかは、リスクの見積もりに影響します。採用しているパッケージは、トークン漏洩による汚染版の公開が起きにくくなっています。

とはいえ、これは公開側の対策です。使う側の防御は別に必要で、依存を取り込むまでに時間差を置く運用が引き続き有効です。この考え方はDependabot の cooldown が既定になったで整理しました。汚染版が公開されてから撤回されるまでの数時間を、そのまま踏まないための仕組みです。

委託先に聞くこと

自社向けのパッケージを外部に作らせている、あるいは保守を委託している場合、次を確認しておくと状況が把握できます。

  1. そのパッケージの公開は、CIから自動で行われているか。人が手元から公開しているなら、また別のリスクの話になります
  2. 公開に使っているトークンは、いつ発行されたものか。長期のまま放置されたトークンが残っている状態については委託先のビルド環境、まだ長期トークンで動いていませんかで扱いました
  3. 段階公開または同等の承認ゲートを入れる予定はあるか。入れない判断でも構いませんが、理由が「知らなかった」なのか「運用上難しい」なのかで、こちらの受け止め方は変わります
  4. 承認できる人は何人いるか。1人なら、その人が抜けたときの手順も併せて確認します

これは委託先を疑う質問ではなく、攻撃が成立する経路を双方で把握しておくための確認です。実際にサプライチェーン経由の事故が起きたとき、いちばん時間を食うのは「どこから入られたか分からない」状態です。攻撃全体の広がりは2026年のサプライチェーン攻撃にまとめています。

次にやること

自社が npm レジストリに公開しているパッケージを1つ選び、そのリリースワークフローを開いてください。確認するのは、npm publish を実行しているステップに、人の承認が一切挟まっていないかどうかです。挟まっていなければ、そのトークンが漏れた時点で汚染版が公開されます。

公開しているパッケージが無い場合は、依存関係のうち社内製・委託先製のものを数えてください。それが実質的に自社のサプライチェーンの範囲です。

リリースフローへの承認ゲートの組み込みや、委託先を含めたビルド環境の権限設計については、グリームハブの開発・AI・自動化のご相談で承っています。開発体制やリリース頻度によって現実的な落としどころは変わるため、個別にご相談ください。お問い合わせからどうぞ。

Sources

URLがコピーされました

グリームハブ株式会社は、変化の激しい時代において、アイデアを形にし、人がもっと自由に、もっと創造的に生きられる世界を目指しています。

記事を書いた人

鈴木 翔

鈴木 翔

技術の可能性に魅了され、学生時代からプログラミングとデジタルアートの分野に深い関心を持つ

関連記事

「TECH」の記事一覧を見る