'Why I stopped trusting npm audit (and built my own)'

Published: (May 4, 2026 at 01:42 PM EDT)
3 min read
Source: Dev.to

Source: Dev.to

Generate a CycloneDX SBOM and deterministic, audit‑ready risk report from your package-lock.json

You run npm audit. It says “47 vulnerabilities.”
Cool. Which ones actually matter? The one in your production bundle? You don’t know.

So you either:

  • Ignore everything → ship anyway
  • Lose signal either way

The real problem isn’t vulnerabilities — it’s decision‑making.

The real problem isn’t vulnerabilities — it’s decision‑making

Most tools answer:

“What is wrong?”

They don’t answer:

“What should I do about it?”

That last question is the real problem.

Enter: audit‑ready

Instead of scores, it gives you decisions. Deterministic. Reproducible. Auditable.

🔑 reasonCode replaces CVSS

Every dependency gets exactly one label, e.g.:

DEV_DEPENDENCY_ONLY

No interpretation required. CI becomes trivial – not “7 high vulnerabilities.”

🧠 The constraint that shapes everything

Same package-lock.json → identical output. Always.

How that’s enforced

Core logic has hard constraints:

const banned = ['Date', 'Date.now()', 'Math.random()', 'process.env'];

If determinism breaks → build fails.

⚙️ The engine is intentionally simple

No scoring. No heuristics.
First match wins – priority is defined by rule order.

🧾 Output you can actually use

Everything is tied to reasonCode.

🔐 Security: this tool audits itself

If you’re generating audit artifacts, your tool has to be trustworthy.

No environment access

The core engine literally cannot read:

  • environment variables

Output depends only on input + tool version

Deterministic PURL generation

Standard encoders (encodeURIComponent, URL) can differ across Node versions, so PURLs are built manually.

  • Same package → same PURL → always

Schema validation (input + output)

If validation fails → nothing is written.

Immutable output

No silent mutation. Exceptions cannot live forever; every exception requires a reason. Expired? audit-ready audit-exceptions → exit 1. No silent ignores.

Network safety by design

Only one external call:

  • OSV API with PURLs

If it fails, the SBOM is still generated. The tool runs its own pipeline on itself – same code, same rules. If it lies, it exposes itself.

⚠️ What this tool does NOT do

If a case isn’t covered → it fails loudly.

Why this matters

This isn’t about better scanning. It’s about reproducible decisions. Production release planned after Phase 3.

💬 Looking for feedback

https://github.com/neve7er/audit-ready

Final thought

Most tools try to be smart. This one tries to be predictable. Because in security, predictability beats intelligence.

0 views
Back to Blog

Related posts

Read more »