Auditfix
Problem
npm audit is broken. It floods CI pipelines with noise because it flags every advisory regardless of production reachability, exploit likelihood, or dependency depth. I built auditfix as a drop-in replacement that only reports what actually matters β production-reachable vulnerabilities scored by real exploit data, with supply chain intelligence and safe auto-fixes.
Constraints
- -Must parse npm, yarn (classic + berry), and pnpm lockfiles without requiring their CLI tools
- -Zero authentication required for basic scanning
- -Offline capability required for air-gapped CI environments
- -Must not introduce command injection vectors
- -Single-file executable via tsup bundling for fast npx startup
Architecture
Four-phase pipeline: lockfile detection and parsing (npm/yarn/pnpm), production reachability analysis (BFS from production roots or npm pre-computed flags), advisory fetching with three-tier fallback (OSV.dev batch API, local cache, bundled offline index), and composite risk scoring (0-100 based on CVSS, EPSS, CISA KEV, production exposure, import chain verification). Supply chain scanner runs in parallel: typosquatting detection via Levenshtein distance, install script analysis, Sigstore provenance verification, and behavioral source code analysis. Output formats: terminal, JSON, SARIF (GitHub Code Scanning), CycloneDX SBOM, OpenVEX.
Tech Choices & Why
OSV.dev batch API
No auth required, batch queries up to 1,000 packages, real-time data. GitHub Advisory GraphQL requires tokens and complex rate limit management.
Graduated EPSS scoring
0-20 point scale instead of binary yes/no. EPSS probability from FIRST.org gives actual exploit likelihood, not just theoretical severity.
tsup (esbuild)
Single-file output with shebang injection. Sub-second npx cold start.
semver with includePrerelease
Without this flag, prerelease versions silently pass through vulnerability checks. A false negative in a security tool is worse than useless.
Challenges & Solutions
Problem
pnpm lockfiles use snapshot keys with peer dependency suffixes that break naive name@version parsing.
Solution
Suffix stripping parser for pnpm v9+ snapshot format. Cross-references importers field for workspace-level dev/production classification.
Problem
OSV version ranges use an event-based format incompatible with node-semver ranges.
Solution
Custom converter mapping OSV event pairs to semver range strings. Handles open-ended ranges, the '0' sentinel, and multiple affected ranges per advisory.
Problem
Risk scoring needed to differentiate a CVSS 9.8 in a dev-only linter from a CVSS 7.0 with a known exploit in production Express.
Solution
Composite score (0-100) weighting production reachability (30 pts), EPSS/KEV exploit data (0-20 pts), CVSS base (0-40 pts), import chain (10 pts), and depth penalty. Critical requires all three: production + exploit + CVSS >= 7.
Trade-offs
- ~Bundled offline index is stale by hours/days (updated at npm publish time). Acceptable as tier-3 fallback.
- ~Import chain analysis uses regex, not AST parsing. Misses dynamic imports and barrel file re-exports.
- ~CISA KEV is US-government-maintained. May miss exploited vulnerabilities not yet cataloged.
- ~Typosquatting Levenshtein distance has false positives for legitimately similar package names.
Impact
Published to npm. Cuts 60-70% of npm audit noise by filtering dev-only vulnerabilities. PR comment bot for GitHub Actions, Teams/Discord webhook notifications, and SARIF diff mode for CI/CD pipelines. 51 source files, 39 test files, 7 production dependencies.
What I'd Improve
- +Add AST-based import analysis to replace regex scanning
- +Add historical trend analysis for vulnerability regression detection
- +Add policy engine for organization-specific severity rules
- +Add transitive license compliance graph
This project was reviewed by Luka (Principal Research Consultant) and Nala (UI/UX Compliance Auditor). They had no comments, which we interpret as approval.