Supply chain attacks don't come from nowhere. They exploit structural conditions that existed long before the incident — single maintainers, token concentration, asymmetric blast radius. The conditions are visible. The question is whether anyone is looking.
We took three of the most consequential npm supply chain attacks in the last eight years and analyzed each one through proof-of-commitment — behavioral scoring that measures structural resilience, not CVE databases. For each incident, we ran the actual package through the API today, then reconstructed what the signals would have shown before the attack.
The results are honest. In some cases, the tool would have flagged the exact vulnerability exploited. In others, the signal was there but below the alarm threshold. We'll show both.
Case 1: event-stream (2018)
What happened
In November 2018, a developer named right9ctrl approached Dominic Tarr, the sole maintainer of event-stream, and offered to take over maintenance of the package. Tarr, who had moved on from the project, agreed. The new maintainer added a dependency called flatmap-stream, which contained an encrypted payload targeting Copay — a Bitcoin wallet — to steal cryptocurrency. The attack went undetected for two months. It targeted a specific downstream package while hiding in a generic utility with ~2 million weekly downloads at the time.
What proof-of-commitment sees today
| Package | Score | Risk | Maintainers | Downloads/wk | Age |
|---|---|---|---|---|---|
| event-stream | 67 | ⚠️ WARN | 1 | 6.0M | 14.7 yrs |
Score: 67 — sitting in the "GOOD" band but well below the "HEALTHY" threshold of 75. The WARN flag fires because of single-maintainer risk. It misses CRITICAL only because downloads are under 10 million per week.
What signals existed before the attack
- Single maintainer — Dominic Tarr was the only person with npm publish access. When he handed the keys over, there was no governance process, no second pair of eyes, no institutional memory.
- Maintainer handoff pattern — A new, unknown contributor took ownership. This is the single strongest behavioral signal for social engineering attacks, and it's the one thing nobody was monitoring.
-
Sudden new dependency — The addition of
flatmap-stream, a brand-new package with no download history, should have been a structural anomaly. An established package suddenly depending on an unknown package is a pattern, not just a diff. - Abandoned project, active downloads — Tarr had publicly stated he was no longer interested in maintaining the package. An abandoned but highly-downloaded package is the ideal target for social engineering.
Verdict: partially
Proof-of-commitment would have flagged the single-maintainer risk — that was the structural condition that made the social engineering attack possible. But it would not have specifically detected the maintainer handoff or the suspicious new dependency.
What it does prove: the structural condition that enabled the attack was observable. One maintainer. No governance. High download count relative to maintainer investment.
Case 2: ua-parser-js (2021)
What happened
In October 2021, the npm account of Faisal Salman — the sole maintainer of ua-parser-js — was compromised. The attacker published three malicious versions that contained a cryptominer and a credential-stealing trojan targeting Linux and Windows systems. The package had approximately 7 million weekly downloads at the time and was used by companies including Facebook, Microsoft, Amazon, and Google. The malicious versions were live for roughly four hours before removal.
What proof-of-commitment sees today
| Package | Score | Risk | Maintainers | Downloads/wk | Age |
|---|---|---|---|---|---|
| ua-parser-js | 83 | 🔴 CRITICAL | 1 | 25.4M | 13.7 yrs |
Today: score 83, single maintainer, 25.4 million weekly downloads. CRITICAL. The exact profile that was exploited.
What signals existed before the attack
- Single maintainer with sole npm token — Faisal Salman was the only person who could publish. One compromised credential = full access to 7 million weekly installs.
- High download-to-maintainer ratio — Even at 7M weekly downloads, the ratio of "people who depend on this" to "people who can publish" was approximately 7,000,000 : 1.
- npm didn't require 2FA at the time — A single password could, and did, compromise the entire package.
- Behavioral score looks fine — This is the uncomfortable part. The package was well-maintained, consistently released, widely adopted. Every quality metric was positive. The vulnerability was invisible to quality analysis.
Verdict: yes
Proof-of-commitment would have flagged this. In 2021, with ~7M weekly downloads, it would have been right at the CRITICAL boundary — WARN at minimum, with the single-maintainer flag clearly visible.
Three years after the attack, nothing has structurally changed. ua-parser-js today still has one maintainer. Downloads have grown from 7M to 25M per week. The blast radius is 3.6x larger than when it was compromised. The same attack would work again, with more damage.
Case 3: colors.js (January 2022)
What happened
In January 2022, Marak Squiress — the sole maintainer of colors.js and faker.js — intentionally published breaking versions of both packages. colors.js v1.4.44 and v1.4.45 introduced an infinite loop that caused any application importing the package to hang indefinitely. The package had approximately 35 million weekly downloads. Hundreds of open source projects and enterprise CI/CD pipelines broke immediately.
Marak had been publicly protesting the fact that large corporations were building commercial products on his unpaid open source work. The sabotage was intentional and announced. The entire incident was enabled by a single structural condition: he was the only person who could publish these packages.
What proof-of-commitment sees today
| Package | Score | Risk | Maintainers | Downloads/wk | Age |
|---|---|---|---|---|---|
| colors | 65 | 🔴 CRITICAL | 1 | 19.8M | 15.1 yrs |
Today: score 65, single maintainer, 19.8 million weekly downloads — and still CRITICAL. The download count has declined from ~35M since the incident damaged ecosystem trust, but the structural profile is unchanged. One person. One token. Millions of installs.
What signals existed before the incident
- CRITICAL flag was present — At ~35M weekly downloads and sole maintainer, colors.js would have been flagged CRITICAL.
- High score provided false comfort — colors.js was a well-maintained package with 15 years of history, consistent releases, and stable download trends. Every quality metric was positive. The risk wasn't about quality — it was about governance.
- No governance structure — There was no second reviewer, no multi-maintainer quorum, no npm organizational account. The entire blast radius rested on one person's continued good will.
- The signal is broader than external attacks — This case proves that CRITICAL flagging isn't only about token compromise. It's about any failure mode of the sole maintainer: burnout, grievance, instability, or compromise.
Verdict: yes, clearly
The CRITICAL flag is explicitly designed for this scenario. Not just external attacks — any failure of the single person at the helm.
npm audit showed nothing before the incident — there were no known vulnerabilities. CVE databases showed nothing. Every toolchain in the ecosystem reported green until the packages broke. The structural flag would have shown red for months.
Summary
| Incident | Attack vector | npm audit | CVE | PoC flag | Would PoC have helped? |
|---|---|---|---|---|---|
| event-stream (2018) | Social engineering | ❌ | ❌ | ⚠️ WARN | Partially — flagged single maintainer, but wouldn't detect handoff |
| ua-parser-js (2021) | Token compromise | ❌ | ❌ | ⚠️ WARN* | Yes — exact vulnerability flagged. *WARN at 2021 volume, CRITICAL today |
| colors.js (2022) | Intentional sabotage | ❌ | ❌ | 🔴 CRITICAL | Yes — sole-maintainer flag visible for entire 15-year package history |
The pattern across all three: zero pre-incident warnings from existing tools. npm audit looks at known CVEs — it can't flag structural risk. CVE databases are reactive by design — they catalog what already happened. Neither tool measures the conditions that make attacks viable.
What We Can't Catch (Yet)
- Maintainer handoffs — The event-stream attack exploited a change in who controls the package. The current scoring is point-in-time; it doesn't track behavioral diffs over time. This is the most important gap.
-
New dependency injection — The addition of
flatmap-streamwas a structural anomaly. Detecting sudden new dependencies in established packages would catch this class of attack. Not implemented yet. - Code-level malice — The tool measures structural governance, not code content. If a trusted maintainer ships malicious code, the structural score won't reflect it. Deliberate scope boundary — structural governance and code analysis are different problems.
What it does catch: the structural conditions that make these attacks possible and high-impact. Single maintainer. Token concentration. Asymmetric blast radius. These conditions precede every attack in this analysis by months or years.
Try It
Run any package through proof-of-commitment in 10 seconds:
npx proof-of-commitment axios ua-parser-js event-stream
# Or your whole project:
npx proof-of-commitment --file package.json
# Or lock files — scans ALL transitive deps:
npx proof-of-commitment --file package-lock.json
Web interface: getcommit.dev/audit
GitHub Action (posts risk table on PRs):
- uses: piiiico/proof-of-commitment@main
with:
fail-on-critical: false
comment-on-pr: true
MCP server for Claude Desktop, Cursor, or Windsurf:
{
"mcpServers": {
"proof-of-commitment": {
"type": "streamable-http",
"url": "https://poc-backend.amdal-dev.workers.dev/mcp"
}
}
}
All data sourced from public npm registry and GitHub APIs. Open source: github.com/piiiico/proof-of-commitment. MIT licensed.
We're building Commit — trust infrastructure for the autonomous economy. Behavioral commitment data, not declarations.
Related: State of npm Trust: April 2026 · The axios signal
Top comments (0)