Overriding nested dependencies in Node.js projects to improve "npm audit" vulnerability report

2.8k views Asked by At

I got some vulnerabilities resolved in my Node.js project by forcing some nested dependency updates but I need help understanding what's actually happening behind the scene of this improvement.

Here is my original "package.json"

{
  "name": "my-app",
  "private": true,
  "version": "3.9.5",
  "description": "my application",
  "keywords": [],
  "dependencies": {
    "@sailshq/connect-redis": "^3.2.1",
    "@sailshq/lodash": "^3.10.3",
    "@sailshq/socket.io-redis": "^5.2.0",
    "axios": "^0.21.1",
    "csv": "^6.0.1",
    "csv-stringify": "^6.0.1",
    "events": "^3.1.0",
    "form-data": "^4.0.0",
    "grunt": "1.4.1",
    "health-check": "1.0.3",
    "kafka-node": "^5.0.0",
    "moment": "^2.26.0",
    "passport": "^0.4.1",
    "passport-oauth2": "^1.5.0",
    "sails": "^1.2.4",
    "sails-hook-grunt": "^5.0.0",
    "sails-hook-orm": "^2.1.1",
    "sails-hook-sockets": "^2.0.1",
    "sails-hook-uploads": "^0.4.3",
    "sails-mongo": "^2.0.0",
    "sails-redis": "^1.0.0",
    "my-inhouse-logger": "3.8.2",
    "url-pattern": "^1.0.3"
  },
  "devDependencies": {
    "eslint": "5.16.0",
    "jest": "^24.9.0",
    "supertest": "^4.0.2"
  },
 "scripts": {
    "start": "NODE_ENV=production node app.js",
    "start:dev": "NODE_ENV=dev sails lift",
    "start-win": "sails lift",
    "test": "NODE_ENV=test jest -c jest.config.js",
    "test:coverage": "npm run test -- --coverage",
    "test:watch": "npm run test -- --watch",
    "test:all": "npm run lint && npm run test:coverage",
    "lint": "./node_modules/eslint/bin/eslint.js . --max-warnings=0 --report-unused-disable-directives && echo '✔  Your .js files look good.'",
    "jest": "NODE_ENV=test jest -c jest.config.js",
    "jest-coverage": "NODE_ENV=test jest -c jest.config.js --coverage --runInBand",
    "jest-no-coverage": "NODE_ENV=test jest -c jest.config.js --runInBand",
    "jest-functional": "NODE_ENV=test jest -c jest.config.functional.js --runInBand",
    "clean": "/bin/bash -c 'rm assets/js/* assets/css/* assets/fonts/* assets/index.html'",
    "custom-tests": "echo \"(No other custom tests yet.)\" && echo"
  },
  "main": "app.js",
  "repository": {
    "type": "git",
    "url": "git://github.com/myprofile/nbackend.git"
  },
  "author": "my name",
  "license": "",
  "engines": {
    "node": "^16.14"
  }
}

When I did "npm install" and then "npm audit", I got

32 vulnerabilities (5 low, 8 moderate, 9 high, 10 critical)

Here is the full report

~/ideaprojects/myapp/backend$ npm audit --registry=https://registry.npmjs.org
# npm audit report

acorn 5.5.0 - 5.7.3
Severity: high
Regular Expression Denial of Service in Acorn - https://github.com/advisories/GHSA-6chw-6frg-f759
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/acorn

ajv <6.12.3
Severity: moderate
Prototype Pollution in Ajv - https://github.com/advisories/GHSA-v88g-cgmw-v5xw
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/ajv
node_modules/sails-hook-grunt/node_modules/eslint/node_modules/ajv
 eslint 4.2.0 - 5.0.0-rc.0
 Depends on vulnerable versions of ajv
 node_modules/sails-hook-grunt/node_modules/eslint

ansi-regex 3.0.0
Severity: moderate
 Inefficient Regular Expression Complexity in chalk/ansi-regex - https://github.com/advisories/GHSA-93q8-gq69-wqmw
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/eslint/node_modules/ansi-regex
node_modules/sails-hook-grunt/node_modules/inquirer/node_modules/ansi-regex
node_modules/sails-hook-grunt/node_modules/string-width/node_modules/ansi-regex

debug <2.6.9
Regular Expression Denial of Service in debug - https://github.com/advisories/GHSA-gxpj-cx7g-858c
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/mocha/node_modules/debug
 mocha 0.6.0 - 6.2.2 || 7.0.0-esm1 - 7.1.0
 Depends on vulnerable versions of debug
 Depends on vulnerable versions of diff
 Depends on vulnerable versions of growl
 Depends on vulnerable versions of mkdirp
 node_modules/sails-hook-grunt/node_modules/mocha

diff <3.5.0
Severity: high
Regular Expression Denial of Service (ReDoS) - https://github.com/advisories/GHSA-h6ch-v84p-w6p9
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/diff
 mocha 0.6.0 - 6.2.2 || 7.0.0-esm1 - 7.1.0
 Depends on vulnerable versions of debug
 Depends on vulnerable versions of diff
 Depends on vulnerable versions of growl
 Depends on vulnerable versions of mkdirp
 node_modules/sails-hook-grunt/node_modules/mocha

engine.io <4.0.0
Severity: high
Resource exhaustion in engine.io  - https://github.com/advisories/GHSA-j4f2-536g-r55m
fix available via `npm audit fix --force`
Will install [email protected], which is a breaking change
node_modules/engine.io
 socket.io 1.0.0-pre - 2.4.1
 Depends on vulnerable versions of engine.io
 node_modules/socket.io
   sails-hook-sockets *
   Depends on vulnerable versions of machinepack-redis
   Depends on vulnerable versions of socket.io
   node_modules/sails-hook-sockets

getobject 0.1.0
Severity: critical
Prototype pollution vulnerability in 'getobject' - https://github.com/advisories/GHSA-957j-59c2-j692
No fix available
node_modules/sails-hook-grunt/node_modules/getobject
 grunt-legacy-util <=2.0.0
 Depends on vulnerable versions of getobject
 node_modules/sails-hook-grunt/node_modules/grunt-legacy-util
   grunt <=1.2.1
   Depends on vulnerable versions of grunt-legacy-util
   node_modules/sails-hook-grunt/node_modules/grunt
     sails-hook-grunt *
     Depends on vulnerable versions of grunt
     node_modules/sails-hook-grunt

growl <1.10.0
Severity: critical
Command Injection in growl - https://github.com/advisories/GHSA-qh2h-chj9-jffq
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/growl
 mocha 0.6.0 - 6.2.2 || 7.0.0-esm1 - 7.1.0
 Depends on vulnerable versions of debug
 Depends on vulnerable versions of diff
 Depends on vulnerable versions of growl
 Depends on vulnerable versions of mkdirp
 node_modules/sails-hook-grunt/node_modules/mocha

grunt <=1.2.1
Severity: critical
Arbitrary Code Execution in grunt - https://github.com/advisories/GHSA-m5pj-vjjf-4m3h
Depends on vulnerable versions of grunt-legacy-util
No fix available
node_modules/sails-hook-grunt/node_modules/grunt
 sails-hook-grunt *
 Depends on vulnerable versions of grunt
 node_modules/sails-hook-grunt

hosted-git-info <2.8.9
Severity: moderate
Regular Expression Denial of Service in hosted-git-info - https://github.com/advisories/GHSA-43f8-2h32-f4cj
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/hosted-git-info

json-schema <0.4.0
Severity: moderate
json-schema is vulnerable to Prototype Pollution - https://github.com/advisories/GHSA-896r-f27r-55mw
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/json-schema
 jsprim 0.3.0 - 1.4.1 || 2.0.0 - 2.0.1
 Depends on vulnerable versions of json-schema
 node_modules/sails-hook-grunt/node_modules/jsprim

lodash <=4.17.20
Severity: critical
Prototype Pollution in lodash - https://github.com/advisories/GHSA-p6mc-m468-83gw
Command Injection in lodash - https://github.com/advisories/GHSA-35jh-r3h4-6jhm
Prototype Pollution in lodash - https://github.com/advisories/GHSA-jf85-cpcp-j695
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/lodash

minimist <=1.2.5
Severity: critical
Prototype Pollution in minimist - https://github.com/advisories/GHSA-xvch-5gv4-984h
Prototype Pollution in minimist - https://github.com/advisories/GHSA-vh95-rmgr-6w4m
Prototype Pollution in minimist - https://github.com/advisories/GHSA-vh95-rmgr-6w4m
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/minimist
node_modules/sails-hook-grunt/node_modules/mkdirp/node_modules/minimist
 mkdirp 0.4.1 - 0.5.1
 Depends on vulnerable versions of minimist
 node_modules/@sailshq/nedb/node_modules/mkdirp
 node_modules/sails-hook-grunt/node_modules/mkdirp
   @sailshq/nedb *
   Depends on vulnerable versions of mkdirp
   node_modules/@sailshq/nedb
     sails-disk >=2.1.1
     Depends on vulnerable versions of @sailshq/nedb
     node_modules/sails-disk
   mocha 0.6.0 - 6.2.2 || 7.0.0-esm1 - 7.1.0
   Depends on vulnerable versions of debug
   Depends on vulnerable versions of diff
   Depends on vulnerable versions of growl
   Depends on vulnerable versions of mkdirp
   node_modules/sails-hook-grunt/node_modules/mocha

path-parse <1.0.7
Severity: moderate
Regular Expression Denial of Service in path-parse - https://github.com/advisories/GHSA-hj48-42vr-x3v9
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/path-parse

redis 2.6.0 - 3.1.0
Potential exponential regex in monitor mode - https://github.com/advisories/GHSA-35q2-47q7-3pc3
fix available via `npm audit fix --force`
Will install [email protected], which is a breaking change
node_modules/redis
node_modules/sails-redis/node_modules/redis
 @sailshq/socket.io-redis *
 Depends on vulnerable versions of redis
 node_modules/@sailshq/socket.io-redis
 machinepack-redis >=1.1.1
 Depends on vulnerable versions of redis
 node_modules/machinepack-redis
 node_modules/sails-redis/node_modules/machinepack-redis
   sails *
   Depends on vulnerable versions of machinepack-redis
   node_modules/sails
   sails-hook-sockets *
   Depends on vulnerable versions of machinepack-redis
   Depends on vulnerable versions of socket.io
   node_modules/sails-hook-sockets
   sails-redis >=1.0.0-0
   Depends on vulnerable versions of machinepack-redis
   node_modules/sails-redis

sails *
Severity: moderate
Prototype Pollution in Sails.js - https://github.com/advisories/GHSA-8v3j-jfg3-v3fv
Depends on vulnerable versions of machinepack-redis
No fix available
node_modules/sails

trim-newlines <3.0.1
Severity: high
Regular Expression Denial of Service in trim-newlines - https://github.com/advisories/GHSA-7p7h-4mm5-852v
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/trim-newlines
 meow 3.4.0 - 5.0.0
 Depends on vulnerable versions of trim-newlines
 node_modules/meow
 node_modules/sails-hook-grunt/node_modules/meow

websocket-extensions <0.1.4
Severity: high
Regular Expression Denial of Service in websocket-extensions (NPM package) - https://github.com/advisories/GHSA-g78m-2chm-r7qv
fix available via `npm audit fix`
node_modules/sails-hook-grunt/node_modules/websocket-extensions

32 vulnerabilities (5 low, 8 moderate, 9 high, 10 critical)

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

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

Some issues need review, and may require choosing
a different dependency.

I added an "overrides" section to "package.json" to force some nested dependency update and improve the vulnerability report. Here is the new "package.json"

{
  "name": "my-app",
  "private": true,
  "version": "3.9.5",
  "description": "my application",
  "keywords": [],
  "dependencies": {
    "@sailshq/connect-redis": "^3.2.1",
    "@sailshq/lodash": "^3.10.3",
    "@sailshq/socket.io-redis": "^5.2.0",
    "axios": "^0.21.1",
    "csv": "^6.0.1",
    "csv-stringify": "^6.0.1",
    "events": "^3.1.0",
    "form-data": "^4.0.0",
    "grunt": "1.4.1",
    "health-check": "1.0.3",
    "kafka-node": "^5.0.0",
    "moment": "^2.26.0",
    "passport": "^0.4.1",
    "passport-oauth2": "^1.5.0",
    "sails": "^1.2.4",
    "sails-hook-grunt": "^5.0.0",
    "sails-hook-orm": "^2.1.1",
    "sails-hook-sockets": "^2.0.1",
    "sails-hook-uploads": "^0.4.3",
    "sails-mongo": "^2.0.0",
    "sails-redis": "^1.0.0",
    "my-inhouse-logger": "3.8.2",
    "url-pattern": "^1.0.3"
  },
  "devDependencies": {
    "eslint": "5.16.0",
    "jest": "^24.9.0",
    "supertest": "^4.0.2"
  },
  "overrides": {
    "grunt": "1.4.1",
    "lodash": "4.17.21",
    "sails-disk": "2.1.1",
    "minimist": "1.2.6",
    "node-notifier": "10.0.1",
    "trim-newlines": "4.0.2",
    "validator": "13.7.0",
    "getobject": "1.0.2",
    "grunt-legacy-util": "2.0.1"
  },
  "scripts": {
    "start": "NODE_ENV=production node app.js",
    "start:dev": "NODE_ENV=dev sails lift",
    "start-win": "sails lift",
    "test": "NODE_ENV=test jest -c jest.config.js",
    "test:coverage": "npm run test -- --coverage",
    "test:watch": "npm run test -- --watch",
    "test:all": "npm run lint && npm run test:coverage",
    "lint": "./node_modules/eslint/bin/eslint.js . --max-warnings=0 --report-unused-disable-directives && echo '✔  Your .js files look good.'",
    "jest": "NODE_ENV=test jest -c jest.config.js",
    "jest-coverage": "NODE_ENV=test jest -c jest.config.js --coverage --runInBand",
    "jest-no-coverage": "NODE_ENV=test jest -c jest.config.js --runInBand",
    "jest-functional": "NODE_ENV=test jest -c jest.config.functional.js --runInBand",
    "clean": "/bin/bash -c 'rm assets/js/* assets/css/* assets/fonts/* assets/index.html'",
    "custom-tests": "echo \"(No other custom tests yet.)\" && echo"
  },
  "main": "app.js",
  "repository": {
    "type": "git",
    "url": "git://github.com/myprofile/nbackend.git"
  },
  "author": "my name",
  "license": "",
  "engines": {
    "node": "^16.14"
  }
}

But I still got the same vulnerability report.

Then in addition to "overrides" in "package.json", based on a suggestion on another question here on Stack Overflow, I also modified "package-lock.json" with just this block bellow that doesn't even look like a normal structure of what we usually have in "package-lock.json"

{
  "dependencies": {
    "sails-hook-grunt": {
      "version": "5.0.0",
      "from": "[email protected]",
      "dependencies": {
        "getobject": {
          "version": "1.0.2",
          "from": "[email protected]"
        },
        "grunt-legacy-util": {
          "version": "2.0.1",
          "from": "[email protected]"
        }
      }
    }
  }
}

Now if I run "npm install" and then "npm audit", I get a much better report like this

8 vulnerabilities (4 low, 1 moderate, 3 high)

Here is the full improved report

~/ideaprojects/myapp/backend$ npm audit --registry=https://registry.npmjs.org
# npm audit report

engine.io <4.0.0
Severity: high
Resource exhaustion in engine.io  - https://github.com/advisories/GHSA-j4f2-536g-r55m
fix available via `npm audit fix --force`
Will install [email protected], which is a breaking change
node_modules/engine.io
 socket.io 1.0.0-pre - 2.4.1
 Depends on vulnerable versions of engine.io
 node_modules/socket.io
   sails-hook-sockets *
   Depends on vulnerable versions of machinepack-redis
   Depends on vulnerable versions of socket.io
   node_modules/sails-hook-sockets

redis 2.6.0 - 3.1.0
Potential exponential regex in monitor mode - https://github.com/advisories/GHSA-35q2-47q7-3pc3
fix available via `npm audit fix --force`
Will install [email protected], which is a breaking change
node_modules/redis
node_modules/sails-redis/node_modules/redis
 @sailshq/socket.io-redis *
 Depends on vulnerable versions of redis
 node_modules/@sailshq/socket.io-redis
 machinepack-redis >=1.1.1
 Depends on vulnerable versions of redis
 node_modules/machinepack-redis
 node_modules/sails-redis/node_modules/machinepack-redis
   sails *
   Depends on vulnerable versions of machinepack-redis
   node_modules/sails
   sails-hook-sockets *
   Depends on vulnerable versions of machinepack-redis
   Depends on vulnerable versions of socket.io
   node_modules/sails-hook-sockets
   sails-redis >=1.0.0-0
   Depends on vulnerable versions of machinepack-redis
   node_modules/sails-redis

sails *
Severity: moderate
Prototype Pollution in Sails.js - https://github.com/advisories/GHSA-8v3j-jfg3-v3fv
Depends on vulnerable versions of machinepack-redis
No fix available
node_modules/sails

8 vulnerabilities (4 low, 1 moderate, 3 high)

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

Some issues need review, and may require choosing
a different dependency.

If I either remove the "overrides" section in "package.json" or not modify "package-lock.json" like I mentioned above I won't get the vulnerability report improved. Looks like I need both.

Even if I do "npm install" again, all the vulnerabilities will get back into the report. And I really don't understand why.

But the main confusion is: how that modification I made to "package-lock.json" helps with a better vulnerability report. I know "npm install" regenerates "package-lock.json" and what I added there should be lost. Does "npm install" consider the dependency I manually added to "package-lock.json" before regenerating it? And why this should matter when I have all the dependencies overridden in my "package.json".

Any help would be appriciated!

1

There are 1 answers

9
Christian Fritz On

As the saying goes, "It's not the things that you don't know that get you into trouble. It's the things that you know for sure but that just ain't so.". In your case:

I know "npm install" regenerates "package-lock.json"

That just ain't true! package-lock.json is only generated if it doesn't exist or when changes are made to the actually installed packages. It's best to think of it as overriding package.json most of the time and I think that's exactly what is happening in your case.

That said, it might be enough to add the overrides section, delete package-lock.json, and re-run npm install to have it be regenerated with, hopefully, the new overrides.