🍇

npm パッケージのセキュリティアップデートをする備忘録

2025/01/21に公開

npmパッケージの依存関係にセキュリティ警告があった際のアップデートについて、自分が進めた備忘録をさくっとまとめてみました。

npm audit

npm auditnpmパッケージ内で依存しているライブラリにおいて、セキュリティ上の既知の脆弱性を持つものを洗い出して警告してくれます。

https://docs.npmjs.com/auditing-package-dependencies-for-security-vulnerabilities

ということでまずはpackage.json直下でnpm auditを実行。

$ npm audit
# npm audit report

@babel/traverse  <7.23.2
Severity: critical
Babel vulnerable to arbitrary code execution when compiling specifically crafted malicious code - https://github.com/advisories/GHSA-67hx-6x53-jw92
fix available via `npm audit fix`
node_modules/@babel/traverse

body-parser  <1.20.3
Severity: high
body-parser vulnerable to denial of service when url encoding is enabled - https://github.com/advisories/GHSA-qwcr-r2fm-qrc7
fix available via `npm audit fix`
node_modules/body-parser
  express  <=4.21.1 || 5.0.0-alpha.1 - 5.0.0
  Depends on vulnerable versions of body-parser
  Depends on vulnerable versions of cookie
  Depends on vulnerable versions of path-to-regexp
  Depends on vulnerable versions of send
  Depends on vulnerable versions of serve-static
  node_modules/express

...

path-to-regexp  <=0.1.11
Severity: high
path-to-regexp outputs backtracking regular expressions - https://github.com/advisories/GHSA-9wv6-86v2-598j
Unpatched `path-to-regexp` ReDoS in 0.1.x - https://github.com/advisories/GHSA-rhx6-c78j-4q9w
fix available via `npm audit fix --force`
Will install gatsby@3.3.1, which is a breaking change
node_modules/gatsby/node_modules/path-to-regexp
node_modules/path-to-regexp

yaml  2.0.0-5 - 2.2.1
Severity: high
Uncaught Exception in yaml - https://github.com/advisories/GHSA-f9xv-q969-pqx4
fix available via `npm audit fix`
node_modules/yaml-loader/node_modules/yaml

29 vulnerabilities (10 low, 4 moderate, 14 high, 1 critical)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

脆弱性が見つかった場合、ヤバさに応じてCriticalからLowまで 4 段階があります。

https://docs.npmjs.com/about-audit-reports#severity

今回の例では、10 つの任意レベル(Low)、4 つの時間がある時にアプデして欲しいレベル(Moderate)、14 個の優先度高くアプデするレベル(High)、1 つのすぐさまアプデしないとダメそうレベル(Critical)のセキュリティレポートを取得したことになります。

npm audit fix

脆弱性のうちfix available via npm audit fixとなっている依存ライブラリは、ライブラリ同士の依存関係に関して互換性のある更新が現状すでにできることを示しています。
こちらがあった折には、とりあえず脳死でサブコマンドのnpm audit fixを実行してみます。脆弱な依存関係に対して、互換性のある更新を自動的にアップデートしてくれます。十中八九うまくいい感じにあってくれます。

fix available via npm audit fix --forceとある場合は、サクッと 1 コマンドで行かないので後回しにします。
npm audit fix --forceはわりと無理やりアップデートしてしまう印象なので、環境自体がぶっ壊れる可能性があるため実行しません。

とりあえずnpm audit fix実行します。

$ npm audit fix
npm warn ERESOLVE overriding peer dependency
npm warn While resolving: react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn Found: react@18.2.0
npm warn node_modules/react
npm warn   react@"^18.2.0" from the root project
npm warn   6 more (@gatsbyjs/reach-router, gatsby, gatsby-link, ...)
npm warn
npm warn Could not resolve dependency:
npm warn peer react@"0.0.0-experimental-c8b778b7f-20220825" from react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn node_modules/react-server-dom-webpack
npm warn   react-server-dom-webpack@"0.0.0-experimental-c8b778b7f-20220825" from gatsby@5.14.1
npm warn   node_modules/gatsby
npm warn
npm warn Conflicting peer dependency: react@0.0.0-experimental-c8b778b7f-20220825
npm warn node_modules/react
npm warn   peer react@"0.0.0-experimental-c8b778b7f-20220825" from react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn   node_modules/react-server-dom-webpack
npm warn     react-server-dom-webpack@"0.0.0-experimental-c8b778b7f-20220825" from gatsby@5.14.1
npm warn     node_modules/gatsby

changed 1 package, and audited 1399 packages in 19s

271 packages are looking for funding
  run `npm fund` for details

# npm audit report

cookie  <0.7.0
cookie accepts cookie name, path, and domain with out of bounds characters - https://github.com/advisories/GHSA-pxg6-pf52-xh8x
fix available via `npm audit fix --force`
Will install gatsby@3.3.1, which is a breaking change
node_modules/cookie
node_modules/gatsby/node_modules/cookie
  engine.io  1.8.0 - 6.6.1
  Depends on vulnerable versions of cookie
  node_modules/engine.io
    socket.io  1.6.0 - 4.7.5
    Depends on vulnerable versions of engine.io
    node_modules/socket.io
      gatsby  >=1.2.0
      Depends on vulnerable versions of babel-plugin-remove-graphql-queries
      Depends on vulnerable versions of cookie
      Depends on vulnerable versions of gatsby-plugin-page-creator
      Depends on vulnerable versions of gatsby-plugin-typescript
      Depends on vulnerable versions of gatsby-plugin-utils
      Depends on vulnerable versions of path-to-regexp
      Depends on vulnerable versions of socket.io
      node_modules/gatsby
        babel-plugin-remove-graphql-queries  3.14.0-alpha-qe-sm.33 - 3.14.0-next.4 || >=4.0.0-alpha-9689ff.4
        Depends on vulnerable versions of gatsby
        node_modules/babel-plugin-remove-graphql-queries
        gatsby-plugin-page-creator  3.14.0-alpha-qe-sm.9 - 3.14.0-next.3 || >=4.0.0-alpha-9689ff.5
        Depends on vulnerable versions of gatsby
        Depends on vulnerable versions of gatsby-plugin-utils
        node_modules/gatsby-plugin-page-creator
        gatsby-plugin-postcss  4.14.0-alpha-qe-sm.46 - 4.14.0-next.2 || >=5.0.0-alpha-9689ff.5
        Depends on vulnerable versions of gatsby
        node_modules/gatsby-plugin-postcss
        gatsby-plugin-typescript  3.14.0-alpha-qe-sm.33 - 3.14.0-next.4 || >=4.0.0-alpha-9689ff.4
        Depends on vulnerable versions of babel-plugin-remove-graphql-queries
        Depends on vulnerable versions of gatsby
        node_modules/gatsby-plugin-typescript
        gatsby-plugin-utils  1.14.0-alpha-qe-sm.46 - 1.14.0-next.2 || >=2.0.0-alpha-9689ff.5
        Depends on vulnerable versions of gatsby
        node_modules/gatsby-plugin-utils

path-to-regexp  <0.1.12
Severity: moderate
Unpatched `path-to-regexp` ReDoS in 0.1.x - https://github.com/advisories/GHSA-rhx6-c78j-4q9w
fix available via `npm audit fix --force`
Will install gatsby@3.3.1, which is a breaking change
node_modules/path-to-regexp

10 vulnerabilities (8 low, 2 moderate)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

cookiepath-to-regexpというのは、自動では互換性を保ってのアップデートができなかったことを示していそうです。

npm outdated

ここでcookiepath-to-regexpのアップデートについて考える前に、これらが依存している大元のライブラリをアップデートすることで解決できないか確認します。
なぜかというと、大元のライブラリをアップデートすることで、もしかしたらライブラリの方で依存ライブラリをメンテしてくれていて、よしなに依存関係もアップデートされるかも?という淡い期待からですね。

$ npm list cookie
my-cording-standards@1.0.0 /Users/moepyxxx/dev/github.com/moepyxxx/cording_standards/my-cording-standards
└─┬ gatsby@5.14.1
  ├── cookie@0.5.0
  ├─┬ express@4.21.2
  │ └── cookie@0.7.1
  └─┬ socket.io@4.7.1
    └─┬ engine.io@6.5.5
      └── cookie@0.4.2

$ npm list path-to-regexp
my-cording-standards@1.0.0 /Users/moepyxxx/dev/github.com/moepyxxx/cording_standards/app
└─┬ gatsby@5.14.1
  ├─┬ express@4.21.2
  │ └── path-to-regexp@0.1.12
  └── path-to-regexp@0.1.10

どちらもgatsbyに依存しているみたいなので、gatsbyがアップデートできれば、もしかしたら望みがあるかもしれません。

npm outdatedコマンドは、package.jsonに記載された主要の依存ライブラリ(dependenciesdevDependenciesなど)の指定したバージョン範囲内において、アップデート可能なものがあるかをチェックしてくれます。

https://docs.npmjs.com/cli/v10/commands/npm-outdated

このバージョン範囲の概念は、ここでは説明を省きますが、他で詳しく載っていますので参考にしてみてください。

https://docs.npmjs.com/cli/v6/using-npm/semver#ranges

いわゆる"hoge": ^1.2.3みたいな指定のことですね。たとえば上記のようにキャレットの記述がある場合、hoge というライブラリはメジャーバージョン(たとえば2.0.0)へのアップデートが許可されていませんが、マイナーアップデートやパッチアップデート(たとえば1.3.01.2.4)は OK としています。

npm outdatedはこの指定の範囲内でアップデートできるものを探してみます。

$ npm outdated
Package            Current    Wanted   Latest  Location                       Depended by
@types/node       20.17.12  20.17.14  22.10.7  node_modules/@types/node       app
@types/react       18.2.56   18.3.18   19.0.7  node_modules/@types/react      app
@types/react-dom   18.2.19    18.3.5   19.0.3  node_modules/@types/react-dom  app
postcss             8.4.49     8.5.1    8.5.1  node_modules/postcss           app
react               18.2.0    18.3.1   19.0.0  node_modules/react             app
react-dom           18.2.0    18.3.1   19.0.0  node_modules/react-dom         app
typescript           5.3.3     5.7.3    5.7.3  node_modules/typescript        app

今回は、なさそうです。gatsbyは最新になっているみたいでした。
念のため以下で最新バージョンも問い合わせてみましたが、package.jsonの中身と突合してみました。

$ npm view gatsby

gatsby@5.14.1 | MIT | deps: 167 | versions: 2979
Blazing fast modern site generator for React
https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby#readme

keywords: blog, generator, jekyll, markdown, react, ssg, website

bin: gatsby

package.json の override

こうなったら、cookiepath-to-regexpの依存ライブラリについては個別でアップデートするしかありません。
package.jsonの override という機能を利用してアップデートします。書き方や制御の方法は細かく指定できるため、公式ドキュメントを覗いてみてください。

https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides

以下のように記載を入れると、依存関係の中で指定されているバージョンをガン無視して、override に記載されたバージョンに無理やり上書きしてくれます。

  "overrides": {
    "cookie": "0.7.1"
  }

ということで、インストールし直してみます。

$ npm install
npm warn ERESOLVE overriding peer dependency
npm warn While resolving: react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn Found: react@18.2.0
npm warn node_modules/react
npm warn   react@"^18.2.0" from the root project
npm warn   6 more (@gatsbyjs/reach-router, gatsby, gatsby-link, ...)
npm warn
npm warn Could not resolve dependency:
npm warn peer react@"0.0.0-experimental-c8b778b7f-20220825" from react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn node_modules/react-server-dom-webpack
npm warn   react-server-dom-webpack@"0.0.0-experimental-c8b778b7f-20220825" from gatsby@5.14.1
npm warn   node_modules/gatsby
npm warn
npm warn Conflicting peer dependency: react@0.0.0-experimental-c8b778b7f-20220825
npm warn node_modules/react
npm warn   peer react@"0.0.0-experimental-c8b778b7f-20220825" from react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn   node_modules/react-server-dom-webpack
npm warn     react-server-dom-webpack@"0.0.0-experimental-c8b778b7f-20220825" from gatsby@5.14.1
npm warn     node_modules/gatsby

removed 2 packages, changed 1 package, and audited 1400 packages in 2s

272 packages are looking for funding
  run `npm fund` for details

2 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

できました!
再度npm auditで検査してみると、cookieライブラリのセキュリティ警告が消えていることが確認できました。

$ npm audit
# npm audit report

path-to-regexp  <0.1.12
Severity: moderate
Unpatched `path-to-regexp` ReDoS in 0.1.x - https://github.com/advisories/GHSA-rhx6-c78j-4q9w
fix available via `npm audit fix --force`
Will install gatsby@5.12.12, which is a breaking change
node_modules/path-to-regexp
  gatsby  3.4.0-alpha-parallel.36 - 3.14.2 || 4.0.0-alpha-9689ff.4 - 4.0.0-zz-next.9 || 5.13.0-alpha-alt-image-cdn.38 - 5.15.0-next.0
  Depends on vulnerable versions of path-to-regexp
  node_modules/gatsby

2 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

同じ要領でpath-to-regexpも上書き&再インストールします。

  "overrides": {
    "cookie": "0.7.1",
    "path-to-regexp": "0.1.12"
  }
$ npm install
npm warn ERESOLVE overriding peer dependency
npm warn While resolving: react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn Found: react@18.2.0
npm warn node_modules/react
npm warn   react@"^18.2.0" from the root project
npm warn   6 more (@gatsbyjs/reach-router, gatsby, gatsby-link, ...)
npm warn
npm warn Could not resolve dependency:
npm warn peer react@"0.0.0-experimental-c8b778b7f-20220825" from react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn node_modules/react-server-dom-webpack
npm warn   react-server-dom-webpack@"0.0.0-experimental-c8b778b7f-20220825" from gatsby@5.14.1
npm warn   node_modules/gatsby
npm warn
npm warn Conflicting peer dependency: react@0.0.0-experimental-c8b778b7f-20220825
npm warn node_modules/react
npm warn   peer react@"0.0.0-experimental-c8b778b7f-20220825" from react-server-dom-webpack@0.0.0-experimental-c8b778b7f-20220825
npm warn   node_modules/react-server-dom-webpack
npm warn     react-server-dom-webpack@"0.0.0-experimental-c8b778b7f-20220825" from gatsby@5.14.1
npm warn     node_modules/gatsby

removed 1 package, changed 1 package, and audited 1399 packages in 1s

272 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
$ npm audit
found 0 vulnerabilities

ということで、きれいになりました 🎉
依存関係を見ると、overriddenとして上書きされたバージョンのライブラリが当たっていることがわかります。npm便利ですね!

$ npm list path-to-regexp
my-cording-standards@1.0.0 /Users/moepyxxx/dev/github.com/moepyxxx/cording_standards/app
└─┬ gatsby@5.14.1
  ├─┬ express@4.21.2
  │ └── path-to-regexp@0.1.12 deduped
  └── path-to-regexp@0.1.12 overridden

ただ、こちらは正直npm audit fix --forceとやっていることはそう変わらないです。
公式の依存関係を無視して上書きするため、メジャーバージョンのアップデートなどは注意が必要で、もちろん動かなくなる可能性もあるかなと思います。
特にメジャーバージョンやマイナーバージョンなど、どかっと上げる場合は、周辺の細やかな動作確認が必要になりそうですね。

また、override は強い制約になるため、このままメンテせず放置していると、対象のパッケージ管理されたライブラリ群は、永遠にライブラリ本来の依存関係を無視して上書きしてしまいます。
たとえばライブラリのアップデートが追いついたら(今回の場合gatsbyがセキュリティ警告に従い、内部のcookiepath-to-regexpパッケージのバージョンをアップグレードしたものをリリースした際)、override 機能の利用を取りやめるといった対応が必要になってきそうです。

アップデートは今必要?

今回の場合は練習がてらセキュリティ警告を 0 にしてみましたが、そもそも全てのセキュリティ警告に従って逐一頑張ってアップデートするべきなの?という点を確認することも大切かなと、個人的には思います。
アップデートは大切ですが、無理やりなアップデートが他の機能を動かなくしてしまったり、override のようにメンテコストや考慮ポイントを生んだり……、思わぬマイナス影響になったりする可能性もありそうかなと。

闇雲にアップデートを頑張るのではなく、以下のような観点も確認してみると良さそうだったりするかもと思っています。

  • cookiepath-to-regexpが使われているライブラリgatsbyの機能群は、自分たちのコードベースでも利用しているのか。
  • セキュリティ警告の警戒レベルはどのくらいか。
  • (実際にライブラリの github を覗きに行って)どのようなセキュリティホールなのか、自分たちのコードベースに影響はあるか。
  • gatsby本体のアップデートを待つ方が面倒くさくないか。

などなど、これらも考えてバランスよくセキュリティアップデートと向き合えるとより良いのかなと思いました ◎
ここまでお読みいただき、ありがとうございました。

Discussion