A03 is no longer "update your dependencies"
The 2021 edition called this category Vulnerable and Outdated Components, and the answer was short: run npm audit, update, done. The 2025 edition renames it Software Supply Chain Failures and moves it to third, because real attacks went through doors that "update your dependencies" does not touch.
The real surface is far wider than package.json:
| Surface | A real attack shape |
|---|
Libraries you declare | A popular package gets malicious code in a patch release |
| Transitive dependencies | You never declared it, but it runs with the same privileges |
| A GitHub Action in CI | An action pinned by tag; the tag is repointed to a different commit |
| The base image | FROM node:20 pulls an image that changed since your last build |
| The build machine | The artefact is built on a compromised runner |
| The distribution path | Somebody pushes a new tag to your own registry |
The two middle rows deserve the most attention because they run with higher privileges than your code: a GitHub Action holds the workflow's privileges, which usually means a repo read/write token and the environment's secrets. A malicious library in your application holds the application process's privileges; a malicious action in CI holds deploy privileges.
And here is the lesson's most important point: "CVE count" is a nearly meaningless metric.
A CVE is only a risk if your code reaches the vulnerable path. Three factors decide, and none of them appears in a CVSS score:
- Is it reachable? A hole in a library's XML parser is unreachable if you only use that library to format dates. This is reachability, and it moves risk by orders of magnitude.
- Does untrusted data get there? A hole needing attacker-controlled input is harmless if the only input is a configuration file you wrote.
- Where does it run? A CVE in a build-only dependency (
devDependencies) does not exist in production — but it does exist in CI, where the secrets are.
The practical consequence: a list of 200 CVEs where 190 are unreachable is a list that gets ignored entirely — the same reason as the grep list in orm-escape-hatches. The work worth doing is not reducing the CVE count but knowing which ones are reachable.
Comments
Commenting needs an account with at least one completed lesson. That condition is what keeps this thread worth reading: every point belongs to someone who can be asked back, and reputation accrues over time.
You can still read every comment below without an account. Signing in brings you back to this exact spot, not to the top of the page.
Loading comments…