はじめに

3月24日にLiteLLMに対するサプライチェーン攻撃があった。自分もLiteLLMを使っているので少しヒヤッとしたが、しばらくinstallやupdateをしていなかったので問題なかった。偶然助かっただけだった。

その後、3月31日にはaxiosに対するサプライチェーン攻撃も話題になった。

axiosのケースは、インストール後に実行されるpost scriptを悪用したものらしい。pnpmはデフォルトでpost scriptを無効にしているため、pnpmユーザーは被害を受けにくいという特徴がある。自分はnpxはほぼ使わないが、信頼できそうなパッケージのnpm installはそれなりにやる。対策を考えておきたい。

サプライチェーン攻撃への現実的な対策

CI環境でのインストール強制、Socketによる監視、バージョンの厳格なロックなど様々な対策があるが、根本的な完全防御は難しい。

注目したいのは、上記の2つのインシデントがいずれも数時間以内に削除・対応されたという点だ。であれば、最新版のインストールに24時間程度のクールダウンを設けるだけで、多くの攻撃を回避できる可能性がある。コスパの良い対策だろう。

pnpmとuvにはこの考え方を実現する機能が備わっている。

pnpm の minimumReleaseAge

pnpmのminimumReleaseAge — pnpm v10.16以降で使える設定。新しく公開されたバージョンのインストールを一定時間遅延させる。

グローバル設定~/.config/pnpm/rc、XDG未設定のmacOSでは ~/Library/Preferences/pnpm/rc):

minimum-release-age=1440
minimum-release-age-exclude[]=@myorg/*

プロジェクト設定pnpm-workspace.yaml):

minimumReleaseAge: 1440  # 24時間(分単位)
minimumReleaseAgeExclude:
  - '@myorg/*'

minimumReleaseAgeExclude で自分の開発パッケージを除外できる。グローバル設定は pnpm dlx(npx相当)にも適用される。npxのaliasをpnpm dlxに向けておくと、npxコマンドがそのまま保護対象になる。

alias npx="pnpm dlx"

uv の exclude-newer

uvのexclude-newer — uvのresolverレベルで適用される設定。指定した期間より前に公開されたバージョンのみを依存関係の解決対象にする。

グローバル設定~/.config/uv/uv.toml):

exclude-newer = "24 hours"

プロジェクト設定pyproject.toml または uv.toml):

[tool.uv]
exclude-newer = "24 hours"
exclude-newer-package = { mypackage = false }

恐らく、uvxにもグローバル設定が適用される。

おわりに

両ツールともグローバル設定に追加してdotfilesにも反映した。インストールやupdateの頻度が低いとはいえ、常時有効にしておくに越したことはない。

参考