npm install直後にマルウェア感染? パッケージの”即インストール”を今すぐやめるべき理由と設定方法

目次

axiosがマルウェアになった日

2026年3月31日、npmで最も使われるHTTPクライアントの1つaxiosに、悪意あるバージョンが公開されました。メンテナのアカウントが乗っ取られ、インストールするだけでリモートアクセスツール(RAT)が仕込まれるバージョンが数時間にわたり配布されたのです。

同じ月には、セキュリティスキャナTrivyのGitHub Actionsが侵害されてCIのシークレットが窃取される事件、そこから波及してPyPIのLiteLLMにマルウェアが混入する事件も発生。1つの侵害が連鎖的に別のプロジェクトに波及する時代に入っています。

ただ、こうした攻撃には共通点があります。悪意あるバージョンの多くは、公開から数時間〜数日で検出・削除されていること。Andrew Nesbittの調査(Package Managers Need to Cool Down)によると、直近のサプライチェーン攻撃10件中8件は1週間以内に対処されていました。つまり、「公開直後のバージョンを即インストールしない」だけで大半の攻撃を回避できたのです。

本記事では、この「即インストールしない」を仕組みで実現する設定方法と、あわせてやっておくべき防御策を紹介します。

なぜ「最新を即インストール」が一番危ないのか

開発者は「最新バージョン=最も安全」と思いがちです。でもサプライチェーン攻撃の文脈では、この常識が逆転します。

【攻撃のタイムライン(axios事件の場合)】

0時間目: 攻撃者がメンテナアカウントを乗っ取り、悪意あるバージョンを公開
  ↓ この間に npm install した人が感染
3時間目: コミュニティが検知、npmから悪意あるバージョンが削除

→ 「公開から3時間以内にインストールした人」だけが被害に遭った

DependabotやRenovateが自動でPRを作り、CIが通ったらマージする。この自動化フローが「公開直後にインストール」を加速させています。自動化は便利ですが、「悪意あるバージョンが公開された直後に自動でマージされる」リスクも同時に抱えていることを認識すべきです。

対策1:クールダウン期間を設定する

「公開から一定期間が経つまでインストールしない」を自動的に実現するのが、パッケージマネージャのクールダウン(min-release-age)設定です。2026年時点で主要なツールはほぼ対応しています。

npm(v11.10.0以降)

プロジェクトルートの.npmrcに1行追加するだけ。単位はです。

# .npmrc
min-release-age=7

これで、公開から7日未満のバージョンはインストール対象から除外されます。CI/CDだけでなくローカルのnpm installにも効きます。公式ドキュメント(npm config – min-release-age)も確認しておきましょう。

pnpm

pnpmは単位がなので注意。7日間は10,080分です。

# pnpm-workspace.yaml
minimumReleaseAge: 10080

Bun

Bunは単位が。7日間は604,800秒。ツールごとに単位がバラバラなのは罠ですが、設定する値さえ間違えなければ効果は同じです。

# bunfig.toml
[install]
minimumReleaseAge = 604800

Dependabot・Renovateにも設定する

パッケージマネージャ側だけでなく、依存関係の自動更新ツール側にもクールダウンを入れないと片手落ちです。

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    cooldown:
      default-days: 7
// renovate.json
{
  "minimumReleaseAge": "7 days"
}

「7日遅れるとセキュリティパッチの適用も遅れるのでは?」という懸念はもっともです。ただ、マルウェアを即インストールするリスクと、正規パッチの適用が1週間遅れるリスクを比べれば、後者の方がはるかに管理しやすい。緊急パッチは手動で対応すると割り切りましょう。

対策2:CIでは必ずロックファイルを厳密に使う

npm installは、package.jsonpackage-lock.jsonに差異があるとロックファイルを更新して新しいバージョンを取得します。CI/CDではロックファイルに記録されたバージョンだけをインストールするコマンドを使ってください。

# CI/CDで使うべきコマンド
npm ci                          # npm
pnpm install --frozen-lockfile  # pnpm
bun install --frozen-lockfile   # Bun

npm ciはロックファイルと不整合があればエラーで止まります。「知らないうちに新しいバージョンが入っていた」を構造的に防げます。

対策3:インストールスクリプトを無効化する

axios事件では、悪意あるパッケージのpostinstallスクリプトが自動実行されることで感染しました。npm installしただけで任意のスクリプトが動く、これがnpmのデフォルト動作です。

# .npmrc(npmの場合)
ignore-scripts=true

これでpostinstall等のスクリプトが自動実行されなくなります。ネイティブモジュールのビルドが必要な場合はnpm rebuild パッケージ名で個別に実行すればOK。

pnpm v10とBunはデフォルトでインストールスクリプトをブロックしてくれます。必要なパッケージだけホワイトリストで許可する方式なので、npmより安全な設計です。

対策4:GitHub Actionsをコミットハッシュで固定する

npmパッケージだけでなく、GitHub Actions自体もサプライチェーン攻撃の対象です。@v4のようなタグ指定は書き換え可能なので、コミットハッシュで固定しましょう。この対策の詳細は、当サイトの別記事でも詳しく解説しています(記事末尾の関連記事セクション参照)。

# ❌ タグ指定(書き換え可能)
- uses: actions/checkout@v4

# ✅ コミットハッシュ固定(改ざん不可)
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

エージェント任せにしすぎないために

DependabotやRenovateは依存関係の管理を効率化してくれる優れたツールです。でも、「PRが来たらCIが通ればマージ」を無思考に繰り返していると、攻撃者にとって最も都合のいいパイプラインを自ら構築してしまいます

自動化ツールと付き合う上で意識しておきたいことを整理します。

  • 自動マージは慎重に:Dependabotの自動マージを有効にしている場合、クールダウン設定と組み合わせないと公開直後のバージョンが即マージされるリスクがある
  • 更新内容を目で確認する習慣:CHANGELOGやdiffを見ずにマージしていませんか? メジャーバージョンアップや見慣れないパッケージの追加は一度立ち止まる
  • 依存の数自体を減らす:使っていないパッケージ、数行で自前実装できるユーティリティは削除する。依存が少ないほど攻撃面が小さい
  • lockfileの差分をレビュー対象にする:PRでpackage-lock.jsonが変更されていたら、何が変わったのかを確認する

便利なツールに任せるのは良いことです。ただ、「任せる」と「放置する」は違う。設定で防げる部分は自動化し、判断が必要な部分は人間が見る。このバランスが、サプライチェーン攻撃への最も現実的な防御線です。

サプライチェーン攻撃対策を深める関連記事

GitHub・セキュリティ

開発環境・ツール

まとめ:「最新」が最も危険な瞬間がある

本記事のポイントを整理します。

  • 2026年3月にaxios・Trivy・LiteLLMと立て続けにサプライチェーン攻撃が発生。悪意あるバージョンの多くは数時間〜数日で削除されている
  • クールダウン設定(min-release-age)で、公開直後のバージョンをインストールしない仕組みを入れる。.npmrcに1行追加するだけ
  • CI/CDではnpm ciを使い、ロックファイルに記録されたバージョンだけをインストールする
  • インストールスクリプトを無効化ignore-scripts=true)して、postinstall経由の感染を防ぐ
  • GitHub Actionsはコミットハッシュで固定して、タグの書き換えによる攻撃を防ぐ
  • 自動化ツールに任せきりにしない。クールダウンと組み合わせ、更新内容を人間が確認する習慣を持つ

「常に最新にしておくのが安全」という感覚は、サプライチェーン攻撃の前では裏目に出ます。公開直後こそ最もリスクが高い瞬間であり、「7日待つ」だけで過去の攻撃の大半を回避できたという事実は重い。今日.npmrcを開いてmin-release-age=7を足す。それが、あなたのプロジェクトを守る最もコスパの高い1行です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次