Model the risk of a supply-chain compromise in an npm dependency tree, explore scenarios, and share a report to convince your boss that you're sitting ducks.
nuxt has a 23.2% modeled chance of at least one package compromise in 1 year.
- Modeled surface
- 512
- packages
- Daily breach prob / package
- 1.41e-6
- scenario assumption
- Time period
- 1 year
- Expected time to breach
- 3.8 years
Every modeled package
- Self
- 1
- Direct deps
- 59
- Transitive deps
- 452
Cumulative breach probability
1 year horizon- All 512 packages
- 23.20%
- Half transitive (286)
- 13.71%
- Self + direct (60)
- 3.05%
Model notes
Click to expandClick to collapse
Each package has a daily breach probability p. With n total modeled packages, including the package itself, the chance that none are breached on a given day is (1 - p)^n.
Over d days, the chance of staying breach-free is (1 - p)^(n x d). The model treats package-days as independent events, a flawed but useful simplification.
p is really two things multiplied: pbreach, the likelihood that a package gets compromised, and pimpacted, the likelihood that a compromise affects you directly. You can only control the latter.
Formula
P(breach) = 1 - (1 - p)n x d
p = pbreach x pimpacted
What can I do about it?
You can't prevent breaches (decrease pbreach). Focus on what you can control:
- Reduce the surface area by removing dependencies (decrease n).
- Reduce the blast radius by defending against common breach patterns (decrease pimpacted).
- Reduce the time window you stay exposed by acting sooner (decrease d).
Fewer packages
Every in the visualization is a package that can be compromised, and most of them are below the iceberg.
- Remove what you don't use. knip finds and removes unused dependencies (and more) adding dead weight and risk. Remove cruft now. Run knip in CI to keep it that way. Donate to sustain it.
- Slim what you do use. A dependency that drags in a huge tree adds more risk than one that doesn't. e18e works with maintainers to cut down those trees and foster lean alternatives. Check out their docs, linter, CI reports, CLI, MCP, and more. Upgrade regularly to benefit for free. Donate to sustain the work.
Fewer open doors
A compromised package only matters if it can actually reach you and do damage.
- Turn off install scripts. Most recent npm attacks fire during install, not at runtime. pnpm 10+, npm 12+, yarn 4.14+, deno, and bun block these by default (yarn 2+ can also opt in); use one of these. Otherwise, prioritize upgrading your package manager.
- Lock down GitHub Actions. There are too many footguns to list here, and that's the point. zizmor performs static analysis of your GitHub Actions workflows and bans insecure usage. Run it once and fix what it flags. Add it to CI to keep it that way. Donate to sustain it.
Two more actionsClick to expandClick to collapse
- Let releases age. Malicious versions are usually pulled within hours, so holding new releases back a short while is a cheap way to reduce risk. pnpm 11+, yarn 4.15+, and deno 2.9+ do this by default; use one of these. With pnpm 10.16+, npm 11.10+, and bun 1.3+ you can opt in. Otherwise, prioritize upgrading your package manager. Renovate and Dependabot can also be configured to delay updates.
- Block flagged packages ASAP. Security researchers like Socket and Snyk typically flag malicious releases within 5 minutes. Socket provides a free CLI that wraps your package manager and blocks flagged packages at install time. Use it in CI and locally.
Act sooner
You decide how much time you spend at your current risk level. Every day adds cumulative risk.
- Take these actions today. Everything in the other two columns only starts paying off the day you do it. Putting them off doesn't hold your risk steady; it keeps accruing for every day of d you spend delaying.