開発eurekapu-nuxt4メモ
npmサプライチェーン攻撃 Shai-Hulud 2.0 への防御設定
claude-code-syncのログを眺めていたら「Shai-Hulud 2.0」という名前が目に飛び込んできた。npm史上最悪のサプライチェーン攻撃だという。正規パッケージのメンテナー認証情報を盗み取り、そのまま悪意あるバージョンをnpmに公開する手口で、npm audit では検出できない。正規パッケージが汚染されるので、依存関係のハッシュだけ見ていても気づけない。
手が止まった。自分のプロジェクトは大丈夫なのか、すぐに確認を始めた。
影響チェック: 感染の兆候なし
複数のチェックを並行で走らせた。
pnpm auditで既知の脆弱性をスキャンpnpm-lock.yamlの最近の変更差分を確認(意図しないバージョン変更がないか)- 依存パッケージの公開日時を確認(直近24時間以内に公開されたバージョンがないか)
結果、感染の兆候は見つからなかった。ひとまず安心したが、攻撃の手口を考えると「今回たまたま踏まなかっただけ」にすぎない。次の波が来る前に防御を張ることにした。
防御設定: minimum-release-age
pnpmには minimum-release-age という設定がある。npmレジストリに公開されてから指定時間が経過していないバージョンのインストールをブロックする。公開直後に仕込まれた悪意あるバージョンは、コミュニティが異変に気づいて取り下げられるまでに数時間〜数日かかる。その「空白の時間」にインストールしないようにするのが狙いだ。
3日(4320分)を設定した。
# ~/.npmrc
minimum-release-age=4320
設定の置き場所を変えた
最初は pnpm-workspace.yaml に書いた。
# pnpm-workspace.yaml(最初の設定 → 削除済み)
packages:
- "apps/*"
onlyBuiltDependencies:
- "@libsql/linux-x64-gnu"
- ...
minimumReleaseAge: 4320
動作は確認できたが、これだとこのモノレポでしか効かない。ほかのプロジェクトで pnpm install したときは素通しになる。
全プロジェクトで効かせるため、~/.npmrc に移動した。グローバル設定なので、どのディレクトリで pnpm install を叩いても3日ルールが適用される。プロジェクトレベルの pnpm-workspace.yaml からは minimumReleaseAge の行を削除して重複を消した。
まとめ
- Shai-Hulud 2.0 は正規パッケージのメンテナー認証情報を盗んで悪意あるバージョンを公開する攻撃。
npm auditでは検出できない - プロジェクトの影響チェックを実施し、感染の兆候なしを確認
minimum-release-age=4320(3日)を~/.npmrcにグローバル設定- 公開から3日以内のバージョンは全プロジェクトでブロックされる
- 完全な防御ではないが、「公開直後の汚染バージョンを踏む」リスクを減らせる