npm audit vs Real Security — What Reddit Overreacts To
npm audit reports 47 vulnerabilities. The Reddit thread says “your site is owned.” Eighteen are in devDependencies (esbuild, testing libs). Twelve are moderate prototype pollution in a CLI you never ship to browsers. Three are real issues in a production HTTP parser. Treating the count as a severity score is how teams either panic-merge breaking upgrades or ignore everything forever.
What audit actually measures
npm audit maps your dependency tree to known advisories (GitHub Advisory / npm DB). It does not:
- Prove the vulnerable function is reachable in your app
- Know whether a
devDependencyruns in production - Replace threat modeling, secret hygiene, or auth bugs you wrote yourself
A high count after adding Storybook is common and often low risk for the deployed artifact.
Triage flow that respects risk
Is the package in the production dependency tree?
no → deprioritize unless it runs in CI with secrets / produces artifacts you publish
yes → is the advisory remotely exploitable in your usage?
no (DoS in unused code path) → schedule, don't page
yes → patch / upgrade / replace now
Commands that help:
npm audit --omit=dev
npm ls <vulnerable-package>
npm why <vulnerable-package>
npm why shows who pulled it in. Sometimes you can override or upgrade a parent instead of living with a transitive ancient version.
Production vs dev vs CI
| Where it runs | Example | Attitude |
|---|---|---|
| Browser/runtime server | express, lodash in API | Treat seriously |
| Build-only | webpack, vite | Risk is supply-chain during build — still real, different controls |
| Local test | jest, jsdom | Rarely your prod RCE surface |
| CI with cloud creds | Any install scripts | Supply-chain matters; pin and review |
Build-time compromise (malicious postinstall) is a real class of attack — but the fix is lockfile integrity, ignored scripts where appropriate, and pinned actions — not fretting every moderate XSS advisory in a markdown parser used only in tests.
npm audit fix is not a strategy
npm audit fix bumps what it can within ranges. npm audit fix --force will install breaking majors and break the build. Prefer:
- Upgrade the direct dependency intentionally.
- Use
overrides/resolutionssparingly for stubborn transitives — document why. - Accept risk explicitly with
npm audit --jsonreviewed in PR, not a blanket ignore file nobody reads.
.npmrc audit=false globally is how you go blind. Narrow exceptions with expiry dates.
Real security work audit will not find
- Hardcoded secrets in the repo
- Open CORS with credentials
- Missing authZ checks on IDs (
/api/orders/123) - Dependency confusion on private registries
- Out-of-date base Docker images
Spend engineering time proportional to exploitability. A critical RCE in a reachable parser beats fifty “moderate” advisories in dead code.
CI policy that does not cry wolf
Fail the build on high/critical findings in production dependencies (npm audit --omit=dev --audit-level=high). Report moderates as warnings with a weekly triage. Pin GitHub Actions and enable dependency review on PRs — supply chain risk is more than advisory CVEs. When an advisory is not reachable, record that analysis in the PR instead of a permanent blank ignore entry.
Green npm audit is a hygiene signal, not a security certification. Red npm audit is a to-do list generator, not an incident. Triage with omit=dev, reachability, and production impact — then patch the few that matter before you rage-upgrade the universe.