[5/5] `npm audit` の high を全部潰す — `overrides` で Next.js の中の古い postcss を上書きする話
`npm audit` で出てた high 脆弱性を全部潰すまでの夜の作業ログ。 Next.js を patch upgrade しても解消されなかった postcss の脆弱性を、 `package.json` の `overrides` で強制更新した話を書きます。
これは Part 4 の続きです。
E2E 自動化を動かして満足してたんですが、 push したあと CI の通知を見たら failure。 内容は npm audit ステップで脆弱性 5 件検出。 ぼくが触ったコードと一切関係ない、 既存の依存パッケージの問題でした。
これは「CI を一時的に緩める」と「Next.js を upgrade して根本対応する」の選択肢があって、 ぼくは両方やりました。 まず CI を緑にして、 そのあと根本対応で overrides を使う、 という流れ。
今日はその夜の作業ログです。
症状: npm audit --omit=dev --audit-level=high で 5 件検出
CI の workflow には IMPL-044 として 本番依存のセキュリティ監査ステップが入ってました。
- name: Security audit (npm audit)
run: npm audit --omit=dev --audit-level=high--omit=dev で dev 依存を除外、 --audit-level=high で high 以上だけ CI を落とす設定です。
そして検出された 5 件はこんな感じ:
Next.js high 系 ×3
- DoS with Server Components
- Cache poisoning via collisions in React Server Component cache-busting
- Middleware / Proxy bypass through dynamic route parameter injection
ほか
postcss moderate ×1
- XSS via Unescaped </style> in its CSS Stringify OutputNext.js 側の脆弱性は最近 GHSA に登録されたやつで、 ぼくの依存範囲(^16.2.0)では当たりにいく。 そして postcss は Next.js の中の node_modules/next/node_modules/postcss が古いまま。
Step 1: 暫定対応として CI の閾値を緩める
push 直後の作業中で根本対応してる時間がなかったので、 まずは CI を通すために閾値を緩めました。
- run: npm audit --omit=dev --audit-level=high
+ run: npm audit --omit=dev --audit-level=criticalcritical まで上げると、 high は警告のみで CI は通る。 ただし TODO コメントは必ず付けて、 根本対応忘れない仕掛けに:
# 2026-05-15: Next.js の high 脆弱性が GHSA に多数登録されたため、
# 根本対応(Next.js upgrade)が完了するまで一時的に critical に緩和。
# TODO: Next.js upgrade 完了後に `--audit-level=high` に戻すこと。「CI 緑にするための緩和」 = 必ず期限付き、 が鉄則。 戻し忘れると無意味になります。
Step 2: Next.js 16.2.4 → 16.2.6 への patch upgrade
npm install next@16.2.616.2.x は patch upgrade なので breaking changes はほぼなし。 ぼくの場合は何のコード修正もなく、 typecheck / lint / build 通りました。
npx tsc --noEmit # ✅ pass
npm run lint # ✅ pass
npm run build # ✅ passStep 3: それでも残った脆弱性
audit 再実行してみると…
@anthropic-ai/sdk moderate (Filesystem Memory Tool 関連)
fast-uri high (path traversal, host confusion)
fast-xml-builder high (attribute escape bypass, comment regex bypass)
postcss moderate (XSS via Unescaped </style>)Next.js の high 系は upgrade で全部解消。 でも他に 4 件残ってる。
fast-uri/fast-xml-builderはnpm audit fixで自動修正可能(non-breaking)@anthropic-ai/sdkは 0.79 → 0.96 で breaking change なので別 PLANpostcssがやっかい
Step 4: npm audit fix で fast-uri と fast-xml-builder を直す
npm audit fixこれで fast-uri / fast-xml-builder の 2 件が消える。 ただし、 ログを見ると postcss の fix は --force 必要 と言ってきます。
Will install next@9.3.3, which is a breaking change何が起きてるかというと、 npm audit fix --force は postcss の脆弱性を解消するために、 Next.js を 9.3.3 にダウングレードしようとする。 つまり「postcss の現行バージョンに依存しない古い Next.js」に戻す動きです。 当然これは受け入れられない。
Step 5: package.json の overrides で postcss を強制更新
ここで overrides 機能の出番です。
overrides は、 依存ツリーの中で「このパッケージは絶対にこのバージョン以上を使え」と強制できる npm の機能。 ぼくの場合は postcss を ^8.5.10 に固定したい。
{
"name": "...",
"overrides": {
"postcss": "^8.5.10"
},
"scripts": { ... },
"dependencies": { ... }
}package.json のトップレベルに overrides を書くだけ。 npm install で node_modules/next/node_modules/postcss も 8.5.10 以上に置き換わります。
npm install
npm audit --omit=dev
# 残るのは moderate 1 件のみ (Anthropic SDK)@anthropic-ai/sdk の moderate は別問題なので別 PLAN にして、 CI の閾値を critical → high に戻しました。
- run: npm audit --omit=dev --audit-level=critical
+ run: npm audit --omit=dev --audit-level=highこれで「high 以上は CI を落とす」の元の運用に戻れます。 残った moderate 1 件はコメントに記録:
# 既知の残存 moderate 脆弱性(2026-05-15 時点):
# - @anthropic-ai/sdk 0.79-0.91(Insecure Default File Permissions in
# Local Filesystem Memory Tool)
# → ぼくのプロダクトでは Filesystem Memory Tool 未使用のため実害ゼロ。
# → 0.96.0 への upgrade は breaking change のため別 PLAN で対応予定。overrides を使うときの注意点
便利な機能ですが、 副作用もあるので 3 つだけ:
- patch / minor 上げの override は割と安全。 major 上げは breaking change を踏みやすい。
- overrides で固定すると
npm audit fixの自動提案が効かなくなる。 そのバージョンが古くなったときに気づきにくい。 定期的に手動で audit を見る運用にする。 - lock ファイル(
package-lock.json)も更新されるので、 必ず commit する。 CI でnpm ciするときに差分が出るとnpm ciが失敗する。
`overrides` を書く判断基準
- 直接の dependency を上げる方が筋がよい(まずは依存先パッケージの最新を確認)
- でも依存先(例: Next.js)がまだ古い版に固定してる場合、 自分のプロジェクトだけ強制更新したい →
overrides - security advisory のためだけに直接の dependency を 1 メジャー上げるのは避けたい →
overrides
「依存先が直してくれるのを待つ」 か 「自分で overrides で先に塞ぐ」 かの判断が必要です。
Step 6: もう 1 個、 CI で別の罠を踏む
ここまでで脆弱性は片付いたんですが、 push したら CI がまた失敗。 今度は別の検出ルールでした。
SECURITY DEFINER without SET search_path detected in 1 migration file(s).
- supabase/migrations/20260324xxxxxx_xxxx.sqlこれは自分で書いた scripts/check-security-definer.sh という Supabase migration 用 linter。 全 SECURITY DEFINER 関数に SET search_path が紐づいてるかチェックするやつです。
該当ファイルを開いてみると、 5 件の SECURITY DEFINER 全てに SET search_path = public が隣接行で付いてる。 ローカルで bash scripts/check-security-definer.sh を走らせると ✅ 通る。
つまり CI 環境(GNU sed)でだけ false-positive。 macOS の BSD sed では通って、 ubuntu の GNU sed では弾かれる、 という方言問題でした。
時間も時間(深夜 3 時)やったので、 まずは ALLOWLIST に追加して CI を通し、 スクリプトの根本対応は別 PLAN に切り出しました。
ALLOWLIST=(
"..."
+ # CI 環境(GNU sed)でのみ false-positive。要・スクリプトの行単位パースへの書き換え。
+ "20260324xxxxxx_xxxx.sql"
)動作確認
最後にもう一度 CI 走らせて、 全 step 緑になることを確認:
git push origin develop
# CI: success (3m30s)
# E2E: success (1m37s) ← Part 4 で組んだやつも稼働中「npm audit --omit=dev --audit-level=high で 0 件、 CI 全 step 緑、 E2E 緑」 の状態でこの夜の作業を終えました。
教訓
npm auditで出る脆弱性は、 直接依存だけじゃなく依存先の依存にも潜む。overridesで叩く選択肢を知っておくと事故対応の幅が広がる。- CI の閾値を緩めるときは TODO コメントを必ず残す。 戻し忘れたら無意味。
- lint スクリプトの方言問題(BSD sed vs GNU sed)はあるある。 sh / awk / sed で書いた CI スクリプトは、 ubuntu(GNU)上で動かして検証するのが安全。
まとめ
今日の Part 5 を含めて、 一晩で:
- Sentry 38 events 撃破
- E2E 自動化セットアップ
- CI 復旧 +
npm audit0 件達成 - Next.js patch upgrade + postcss override
…と、 結構な量を片付けました。 翌朝(つまり今)、 CI / E2E の両方が緑で、 Sentry も静かな状態で迎えられたのはほんと気持ちええです。
そして全部、 AI(愛)と一緒に進めた一晩の出来事。 ひとりで考えてたら、 多分 overrides の存在に気づかず Next.js を major upgrade して別の事故を踏んでたと思います。
「AI と一晩 14 commit 編」シリーズはこれで完結です。 Part 1 から読み直してみると、 env トラブル → ツール卒業 → 本番障害 → 自動化 → 依存管理、 という典型的な「インフラ整備の一夜」を辿ってます。 似た状況にハマってる人の参考になれば嬉しいです。