Dependency Risk: Auditing Your Third-Party Packages
Your app is mostly code you didn’t write
Run a quick count on any modern web project: lines of code you wrote versus lines sitting in node_modules or your virtualenv. The ratio is rarely better than 1:20 and often worse than 1:100. Every audit of “your” codebase is therefore, by volume, mostly an audit of your decisions about other people’s code: what you pulled in, whether it’s maintained, whether it’s carrying known holes, and whether anything in the install pipeline could be tampered with.
Teams tend to sit at one of two unhelpful extremes: ignoring npm audit output entirely (“it’s always red, it’s noise”), or panicking at every critical CVE regardless of relevance. Both are wrong, and the audit’s job is to replace them with something rational: triage by reachability.
CVEs: severity is not risk
Here’s the uncomfortable stat every auditor knows from experience: the overwhelming majority of “critical” findings from a dependency scanner don’t matter to your application; research on vulnerability reachability consistently puts exploitable-in-context findings at a small fraction of the raw total. A vulnerability is only your problem if the vulnerable code path is reachable with attacker-controlled input in your app.
Consider two hypothetical findings from the same scan:
- Critical: prototype pollution in a deep-merge utility. But your app only ever calls it on two hardcoded config objects at boot. Real risk: near zero. Fix at leisure.
- Moderate: header-parsing flaw in your HTTP framework’s multipart handler. Your app accepts file uploads from the public internet. Real risk: high. Fix this week.
A scanner ranks these backwards. A human ranks them correctly, and that ranking, applied across your whole manifest, is the difference between a dependency audit and a dependency printout. It’s the same scanner-vs-context gap that runs through everything a manual audit catches.
The audit workflow is: run the scanner (npm audit, pip-audit, cargo audit, or an SCA tool like osv-scanner), then for each critical/high finding ask three questions (Is the vulnerable function actually called? Can attacker input reach it? Is there a mitigating layer in front?) and re-rank accordingly.
The risks scanners don’t score at all
CVE scanning is the known-vulnerability layer. The audit spends at least as much time on the categories with no database entry.
Abandonment
An unmaintained package has no CVEs because nobody is looking, which is worse than having them. Signals the audit checks: last release date, open-issue trajectory, whether the maintainer has archived the repo or publicly walked away, and bus factor (how much of your stack depends on one person’s weekends; the left-pad and colors/faker incidents were both bus-factor stories, one an unpublish, one a maintainer protest-sabotaging his own packages).
Overexposure
Every dependency is attack surface and an upgrade obligation. The audit flags packages that buy you almost nothing: the one-liner utilities (is-odd and friends), the heavyweight library imported for a single function, the three date libraries doing one job. Fewer dependencies isn’t aesthetic minimalism; it’s a smaller supply chain to defend. This overlaps heavily with general codebase hygiene; see what “good code” looks like to an auditor.
Install-time execution
npm install runs arbitrary code via lifecycle scripts (postinstall), on every developer laptop and CI runner you have. Real-world supply-chain attacks (event-stream in 2018, ua-parser-js in 2021, the recurring waves of typosquats) overwhelmingly deliver their payloads this way. Mitigations the audit looks for: --ignore-scripts in CI where feasible, lockfiles committed and enforced (npm ci, not npm install, in pipelines), and dependency-review gates on PRs.
Typosquats and hallucinated packages
Two variants of the same trap. Classic typosquatting registers lodahs hoping for a fat-fingered install. The newer variant: LLM coding assistants sometimes confidently import packages that don’t exist, and attackers register those names (“slopsquatting”). If AI writes a meaningful share of your code, your dependency manifest deserves a suspicion pass; this is one of several failure modes covered in hidden debt in AI-generated code.
License risk
Not a security issue, but a due-diligence one that audits routinely surface: a copyleft (GPL/AGPL) dependency linked into a proprietary SaaS can become a genuine problem during acquisition or enterprise sales review. Cheaper to know now.
The dependency checklist
What we verify on the dependency pass of an audit:
- Lockfile present, committed, and actually used in CI (
npm ci/pip install -rwith hashes / frozen lockfile) - Vulnerability scan run and criticals/highs triaged by reachability, not raw severity
- No dependencies unmaintained > ~2 years on security-relevant paths (auth, crypto, parsing, serialization)
- Direct dependency count sane for the app’s size; no trivial-utility imports
- Pinning strategy is deliberate: ranges + lockfile + automated update PRs (Renovate/Dependabot), or strict pins with a scheduled review, not “whatever resolves today”
- Update PRs actually get merged (a Dependabot queue with 200 open PRs is a decision to stay vulnerable, made passively)
- CI doesn’t run lifecycle scripts it doesn’t need; tokens available to the install step are minimal
- No internal package names resolvable from the public registry (dependency-confusion check)
- Licenses inventoried; no copyleft surprises in the distribution path
The update-cadence question
The healthiest posture we see isn’t “always latest” (you become the ecosystem’s beta tester and the first victim of malicious releases; waiting a few days before adopting fresh releases is a legitimate defense) nor “frozen since 2024” (upgrades compound until they’re a rewrite). It’s boring cadence: automated update PRs, batched weekly, merged behind CI, with security patches fast-tracked. Dependency updates are the one chore where consistency beats heroics; six-monthly “upgrade sprints” are how teams end up three major versions behind on their framework with no incremental path back.
Get a free code audit
The dependency pass (scan, reachability triage, abandonment review, supply-chain hygiene) is part of every free audit we run. Genuinely free: a Webisoft engineer reviews your repository manually and sends a written report that tells you which of your scanner’s findings actually matter, which packages are quietly rotting, and what to fix first. If your npm audit output has been red for six months and nobody knows which lines to care about, get a free code audit. Turning that noise into a ranked list is exactly what it’s for.