ちょっと雑ですが、npmパッケージのバージョンアップと脆弱性対応の方法をまとめました。これがベストかはわからないけど、一つのやり方として紹介します。

node: v14.15.1
npm: v8.1.3

パッケージのバージョンアップ

  • バージョンアップ必要なパッケージを調査

    • npm-check-updatesをインストール

      npm install -g npm-check-updates
    • バージョンアップが必要なパッケージをリストアップ

      ncu
      
      > @nuxtjs/eslint-config               5.0.0  →   6.0.1
      > @nuxtjs/eslint-config-typescript    3.0.0  →   6.0.1
      > eslint                             7.24.0  →   8.1.0
      > eslint-config-prettier              7.2.0  →   8.3.0
      > eslint-plugin-prettier              3.3.0  →   4.0.0
      > eslint-webpack-plugin               2.4.1  →   3.0.1
  • バージョンを書き換え

    • 上記内容で package.json を最新バージョンに書き換え

      ncu -u
    • 修正後の package.json でインストール

      npm install
      
      > npm ERR! While resolving: xxx@1.0.0
      > npm ERR! Found: eslint@8.1.0
      > npm ERR! node_modules/eslint
      > npm ERR!   dev eslint@"8.1.0" from the root project
      > npm ERR! 
      > npm ERR! Could not resolve dependency:
      > npm ERR! peer eslint@"^7.27.0" from @nuxtjs/eslint-config@6.0.1
      > npm ERR! node_modules/@nuxtjs/eslint-config
      > npm ERR!   dev @nuxtjs/eslint-config@"6.0.1" from the root project

      => 今回は以下のバージョンコンフリクトが発生した

      • ルートでeslint@8.1.0が指定されている
      • @nuxtjs/eslint-config@6.0.1eslint@"^7.27.0" (>=7.27.0 && <8.0.0) に依存している
  • コンフリクトしたバージョンを調整

    • pakcage.json を修正

      npm install eslint@7.32.0

      => eslint を 8.1.0 => 7.32.0 (7系の最新) 戻している

    • 改めてインストール

      npm install

      => エラーなくインストールできたので完了

脆弱性を含むパッケージを確認

  • リストアップ

    npm audit
    
    > (一部抜粋)
    > glob-parent  <5.1.2
    > Severity: high
    > Regular expression denial of service - https://github.com/advisories/GHSA-ww39-953v-wcq6
    > fix available via `npm audit fix --force`
    > Will install nuxt@2.13.3, which is a breaking change
    > node_modules/scssfmt/node_modules/glob-parent
    > node_modules/watchpack-chokidar2/node_modules/glob-parent
    >   chokidar  1.0.0-rc1 - 2.1.8
    >   Depends on vulnerable versions of glob-parent
    >   node_modules/scssfmt/node_modules/chokidar
    >   node_modules/watchpack-chokidar2/node_modules/chokidar
    >    scssfmt  *
    >    Depends on vulnerable versions of chokidar
    >    Depends on vulnerable versions of globby
    >    node_modules/scssfmt
    >    watchpack-chokidar2  *
    >    Depends on vulnerable versions of chokidar
    >    node_modules/watchpack-chokidar2
    >      watchpack  1.7.2 - 1.7.5
    >      Depends on vulnerable versions of watchpack-chokidar2
    >      node_modules/watchpack
    >        webpack  4.44.0 - 4.46.0
    >        Depends on vulnerable versions of watchpack
    >        node_modules/webpack
    >          @nuxt/webpack  *
    >          Depends on vulnerable versions of cssnano
    >          Depends on vulnerable versions of webpack
    >          node_modules/@nuxt/webpack
    >            @nuxt/builder  >=2.14.0
    >            Depends on vulnerable versions of @nuxt/webpack
    >            node_modules/@nuxt/builder
    >            nuxt  >=2.14.0
    >            Depends on vulnerable versions of @nuxt/webpack
    >            node_modules/nuxt
    >   fast-glob  <=2.2.7
    >   Depends on vulnerable versions of glob-parent
    >   node_modules/scssfmt/node_modules/fast-glob
    >    globby  8.0.0 - 9.2.0
    >    Depends on vulnerable versions of fast-glob
    >    node_modules/scssfmt/node_modules/globby
    
    > 30 vulnerabilities (7 moderate, 23 high)
    • 読み方
      • glob-parent <5.1.2
        • glob-parentのバージョンが5.1.2未満は脆弱性を含む。5.1.2以上にアップデート必要
      • 脆弱性の詳細: https://github.com/advisories/GHSA-ww39-953v-wcq6
        • 正規表現を利用したReDoS攻撃に関する脆弱性があるらしい
        • npm audit fix --forceで fix できるけど、nuxt2.13.3に戻ってしまう
      • nuxt => @nuxt/webpack => webpack => watchpack-chokidar2 => chokidar => glob-parent のように依存している
  • 脆弱性を含むパッケージの依存ツリーを確認

    npm ls glob-parent
    
    xxx@1.0.0
    ├─┬ eslint-webpack-plugin@3.0.1
    │ └─┬ webpack@4.46.0
    │   └─┬ watchpack@1.7.5
    │     └─┬ watchpack-chokidar2@2.0.1
    │       └─┬ chokidar@2.1.8
    │         └── glob-parent@3.1.0
    ├─┬ eslint@7.27.0
    │ └── glob-parent@5.1.2
    ├─┬ sass@1.43.3
    │ └─┬ chokidar@3.5.2
    │   └── glob-parent@5.1.2 deduped
    ├─┬ scssfmt@1.0.7
    │ ├─┬ chokidar@2.1.8
    │ │ └── glob-parent@3.1.0
    │ └─┬ globby@8.0.2
    │   └─┬ fast-glob@2.2.7
    │     └── glob-parent@3.1.0 deduped
    └─┬ stylelint@14.0.0
      └─┬ fast-glob@3.2.7
        └── glob-parent@5.1.2 deduped

    => どのパッケージからの依存関係でインストールされているかを確認できる

脆弱性を含むパッケージを対処

脆弱性を含むパッケージを利用しないバージョンに強制的に戻す

npm audit fix --force

=> これで解決することもあるけど、例えばこのケースだと肝心のnuxtのバージョンが下がってしまうので、今回は使えない(nuxtのバージョンを上げることが目的の一つなので)。

脆弱性を含むパッケージのバージョンを強制的にあげる

この方法だと、脆弱性は解決されますが、依存パッケージのバージョンの範囲を超えて、強制的に脆弱性を含むパッケージのバージョンを上げることになるので、問題なく動作するかどうかは分かりません(保証されません)。
従って、予期しないエラーや動作が発生する可能性がありますので、脆弱性のリスクとこの対応をすることによるリスクを比較して、本当に対応するかを検討する必要があります。
また、対応する場合は、動作確認を手厚くおこないましょう。

  • npm-force-resolutionsをインストール

    npm -g install npm-force-resolutions -D
  • package.jsonresolutions の設定を追加

    "resolutions": {
      "glob-parent": "^5.1.2"
    }
  • 指定したパッケージのバージョンを強制的にアップデート

    npx npm-force-resolutions

    => これにより、package-lock.json が強制的に書き換える

  • package-lock.jsonを元にインストールする

    npm ci

    => npm installだと、package.jsonをもとにインストールされるのでもとに戻ってしまうので要注意。

  • パッケージが更新されたか確認

    • 脆弱性確認

      npm audit
      
      (一部抜粋)
      > 10 moderate severity vulnerabilities

      => glob-parentはリストアップされなくなった

    • パッケージのバージョン確認

      xxx
      ├─┬ eslint-webpack-plugin@3.0.1
      │ └─┬ webpack@4.46.0
      │   └─┬ watchpack@1.7.5
      │     └─┬ watchpack-chokidar2@2.0.1
      │       └─┬ chokidar@2.1.8
      │         └── glob-parent@^5.1.2 invalid: "^3.1.0" from node_modules/watchpack-chokidar2/node_modules/chokidar
      ├─┬ eslint@7.27.0
      │ └── glob-parent@^5.1.2 invalid: "^5.0.0" from node_modules/eslint
      ├─┬ sass@1.43.3
      │ └─┬ chokidar@3.5.2
      │   └── glob-parent@^5.1.2 invalid: "~5.1.2" from node_modules/chokidar
      ├─┬ scssfmt@1.0.7
      │ ├─┬ chokidar@2.1.8
      │ │ └── glob-parent@^5.1.2 invalid: "^3.1.0" from node_modules/scssfmt/node_modules/chokidar
      │ └─┬ globby@8.0.2
      │   └─┬ fast-glob@2.2.7
      │     └── glob-parent@^5.1.2 invalid: "^3.1.0" from node_modules/scssfmt/node_modules/fast-glob
      └─┬ stylelint@14.0.0
        └─┬ fast-glob@3.2.7
          └── glob-parent@^5.1.2 invalid: "^5.1.2" from node_modules/fast-glob

      => 強制的にバージョンを変えているのでinvalidになっているけど、5.1.2以降の5系の最新が指定されている

  • 動作確認
    一通りアプリを動かして、問題ないか確認する。今回は問題なく動いた

  • (参考)npx npm-force-resolutionsの影響調査
    今後、パッケージを追加する時に、何か考慮する必要があるかを調べておく

    • 新しいパッケージを追加したときに、glob-parentがもとに戻るか

      npm install serverless

      => 問題なし(脆弱性を含むバージョンには戻らなかった)

    • パッケージを削除した際に、glob-parentがもとに戻るか

      npm uninstall serverless

      => 問題なし(脆弱性を含むバージョンには戻らなかった)

    • glob-parent自体のバージョンを変更できるか

      npm install -D glob-parent@3
      
      > npm ERR! Invalid Version: ^5.1.2

      => エラー発生。変更するには一旦package-lock.jsonを削除してやり直す必要あり