依存元からの再解決の開発
- 状態: 実装済み(本番運用環境で PR の作成を確認)
- 開始日: 2026年10月15日
- 最終更新: 2026年10月18日
目的
依存元の古い版指定のために直せない脆弱性を、依存元ごとプロジェクトの指定範囲内で上げて直せるようにする。 その際に脆弱性が増えていないかを、依存関係の位置ごとに確かめる。
依存元ごと上げて直す仕組み
修正 PR の運用で、@nestjs/platform-express 11.1.27 が multer を「2.1.1 ちょうど」に指定していたため、multer だけの更新では脆弱性を直せなかった。
更新前: プロジェクト → @nestjs/platform-express 11.1.27 → multer 2.1.1(脆弱)
更新後: プロジェクト → @nestjs/platform-express 11.2.7 → multer 2.4.0
依存元の @nestjs/platform-express を、プロジェクトの package.json の指定範囲内で新しい版に上げることで、multer も修正版になる。
これが依存元からの再解決である。
版はパッケージマネージャーが指定範囲内で選び直し、KestreLynx は範囲を広げない。
以前は依存元を通知に出す案も検討したが、依存元が分かるなら依存元ごと上げればよいと判断した。
方針
- 通常の更新を先に行い、依存元の指定が原因と証明できる場合だけ再解決する
- 通常の更新で直せるものまで、依存元を上げる対象に含めないため
- 一番上の直接依存からプロジェクトの指定範囲内で解決し直し、範囲は広げず、
overridesは使わない- プロジェクトが許している版の条件を守るため
- 新しく入る版は公開から72時間待つ
- 公開直後の版をすぐに取り込まないため
仕組みは依存元からの再解決、対応範囲と上限は再解決の対応範囲と上限にまとめている。
決めたこと
脆弱性を増やさないための検査
一番上の直接依存を上げると、その下にあるほかのパッケージも動くため、脆弱性が増える懸念があった。 そのため、次の条件を採用した。
- どの依存経路でも版が下がらない
- 通常更新の対象と再解決の起点を除き、ほかの直接依存は変わらない
- 更新によって脆弱性が増えない
持ち越しの扱い
パッケージ名・版・脆弱性 ID を厳しく比べると、依存元が指定範囲内で直せない別の脆弱性を持っているだけで、ほとんど不合格になる。 そこで、同じ位置で版だけが変わり、同じ脆弱性が残る場合は「持ち越し」として認めることにした。
この例では、Y に残る CVE-2 を持ち越しとして扱う。
持ち越した脆弱性は直らず、今回直したい脆弱性を持ち越して合格にはできない。
位置ごとの検査
更新前: プロジェクト → A → X 1.0(脆弱性なし)
プロジェクト → B → X 2.0(CVE-9 あり)
更新後: プロジェクト → A → X 2.0(CVE-9 あり)
プロジェクト → B(X を使わなくなった)
「CVE-9 を持つ X」は更新前も更新後も1つで、件数は増えていない。 しかし、A の位置では脆弱性のなかった X が CVE-9 を持つ X に変わっているため、不合格になる。
- 更新後に変わった依存関係それぞれについて、プロジェクトから同じ道筋をたどった更新前の位置を探す
- その位置の旧版と比べて、新しい脆弱性がないかを確かめる
- 更新前の位置が見つからない場合や、一つに決まらない場合は採用しない
位置ごとの検査では、次の変化があると、件数が増えていなくても更新を採用しない。
次の表では、→ は依存関係、⇒ は更新前から更新後への変化を表す。
| 変化 | 例(更新前 ⇒ 更新後) | 採用しない理由 |
|---|---|---|
| 脆弱な新しいパッケージが入る | A(X なし) ⇒ A → X(脆弱) |
更新前の同じ位置に X がなく、脆弱性の持ち越しとして扱えない |
| 脆弱なパッケージを使う依存元が増える | A → X(脆弱) ⇒ A → X(脆弱), B → X(脆弱) |
B の位置に脆弱な X が新しく入る |
| 新しい版に旧版にない脆弱性がある | A → X 1.0(CVE-2) ⇒ A → X 2.0(CVE-2, CVE-9) |
同じ位置の旧版になかった CVE-9 が加わる |
| 1つの版が複数の脆弱な版に分かれる | A → X 1.0, B → X 1.0 ⇒ A → X 1.1(脆弱), B → X 1.2(脆弱) |
旧版から複数の脆弱な版への分岐は、持ち越しとして扱えない |
| 複数の経路が1つに合流する | A → X 1.0, B → X 2.0 ⇒ A → X 3.0, B → X 3.0 |
合流後の X と比べる旧版を一つに決められない |
詳しい条件は再解決の検査条件にまとめている。
検証方法と結果
実際のパッケージマネージャーを動かす結合テスト
npm 10、pnpm 9.15.9・10.34.4・12.11.2、uv 0.13 を使い、再解決と検査の結果を確認した。
- npm・pnpm では、
mkdirp 0.5.1 → minimist 0.0.8の例で、直接依存はmkdirpだけが上がり、minimistが修正版になることを確認した rc 1.2.8 → minimist ^1.2.0の経路は通常の更新で直せるため、rcの版を変えないことを確認した- 依存元を上げても対象の脆弱性を直せない場合に、不合格になることを確認した
- uv では、
pyopensslの脆弱性は持ち越しに当たるが、cryptographyに新しい脆弱性が入るため、不合格になることを確認した
本番運用環境での確認
2026年10月18日、反映後の最初の処理で、@nestjs/platform-express を 11.1.27 から 11.2.7 に上げ、multer を 2.1.1 から 2.4.0 にする PR が作られた。
位置ごとの検査も通った。 次の回は同じ内容の更新を再実行せず、既存の PR に対応付けた。
未検証・次の作業
- 本番運用環境で作られた PR のマージ後の確認
- 持ち越しを認めて採用する例は、結合テストの深刻度設定(HIGH・CRITICAL)では作れず、単体テストだけで確認
- pip は依存元からの再解決の対象外
- 上限の既定値を裏付ける実測
更新履歴
2026年10月18日
- 依存元からの再解決の方針と検査
- 持ち越しと位置ごとの検査
- 結合テストと本番運用環境での確認
この記事は、KestreLynxの開発記録です。KestreLynxについて