You did not audit that dependency and neither did I
A practical model for supply chain risk that doesn't require pretending you read 40,000 files of transitive JavaScript.
Run npm ls --all on a mid-sized frontend project. Count the packages. It is probably somewhere between eight hundred and two thousand. Now ask yourself, honestly, how many of those you have looked at.
The answer is zero, and the answer is zero for everyone, and the security advice industry has spent a decade pretending otherwise.
the useless advice#
"Audit your dependencies." Nobody does this. It is not a discipline problem, it is an arithmetic problem. Two thousand packages at even five minutes each is eighty engineer-days, for one project, once, and it is invalidated by the next npm update.
"Minimize dependencies." Good advice that does not scale. You are not writing your own date library, and if you did it would have more bugs than the one you avoided.
"Use a lockfile." Necessary and completely insufficient. A lockfile pins you to a specific version of the compromised package.
the useful model#
Stop trying to verify code. Start managing blast radius and time to detect.
Blast radius. Ask: if this package were malicious right now, what could it reach? A dev-only dependency that runs in CI can read your CI secrets — that is a large blast radius, and most people classify dev dependencies as low risk, which is exactly backwards. A package in your production server can reach your database. A package in your build step can modify your output artifact, which is the worst one, because it is silent.
Concretely:
- Separate the CI credentials that can publish from the ones that can test. Publishing should require a manual approval or a protected environment, always.
- Run installs with lifecycle scripts disabled where you can.
npm ci --ignore-scriptsfor the test job costs you almost nothing on most trees. - Do not put long-lived cloud credentials in the same job that runs
npm installon a third-party tree. Use OIDC federation with a short-lived token scoped to what the job needs.
Time to detect. Most supply chain compromises are discovered within hours to days, usually by someone noticing weird network traffic or a suspicious diff. The question is whether you shipped during the window.
- Pin exact versions in production. Not ranges.
1.2.3, not^1.2.3. - Delay adoption. A cooldown of even 24 to 72 hours before a new version enters your tree catches an enormous fraction of real-world incidents, because the attacker's window is short and loud. Several tools now do this automatically; Renovate calls it
minimumReleaseAge. - Subscribe to advisories for the fifty packages that actually matter, not all two thousand.
the two changes with the best ratio#
If you do nothing else:
- Turn off install scripts in CI. The overwhelming majority of npm compromise payloads are in a
postinstall. This one flag defeats most of them. - Make publishing require a human. Trusted publishing via OIDC, provenance attestations, and a protected environment. The most damaging incidents are maintainer account takeovers, and a stolen token that cannot publish is worthless.
the thing nobody wants to say#
You are trusting hundreds of strangers, most of whom are unpaid, several of whom are burned out, at least one of whom will eventually hand their package to someone they should not have.
That trust is not going away, because the alternative is not writing software. The job is not to eliminate the trust. It is to make sure that when it is betrayed — and it will be, on a schedule — the damage is contained and you find out fast.
— Dom, February 12, 2025