Safeguard
Open Source Security

Compromised maintainer accounts on npm

Recent npm maintainer account takeovers show how a single stolen credential can compromise billions of downloads. Here's the anatomy of the threat—and the defense.

Safeguard Research Team
Research
7 min read

San Francisco — July 2026. In the past ten months, npm's package registry has weathered at least two supply chain incidents severe enough to make front-page security news: a September 2025 phishing campaign that compromised the maintainer account behind chalk, debug, ansi-styles, and a dozen other foundational packages collectively pulling in over a billion weekly downloads, and the self-propagating "Shai-Hulud" worm that used stolen npm tokens to silently republish trojanized versions of hundreds of packages before harvesting cloud credentials and CI secrets from downstream builds. Neither incident relied on a novel zero-day. Both relied on the oldest trick in the book — tricking or coercing a human who holds publish rights — and both are part of a broader pattern that security researchers have been flagging for years: maintainer account takeover has quietly become the single most efficient way to compromise the open source software supply chain at scale.

This is not a hypothetical risk. It is a documented, recurring event class with a growing body of case studies — event-stream in 2018, ua-parser-js in 2021, coa and rc in the same week of 2021, node-ipc in 2022, and the two 2025 incidents above. Each followed a similar shape: an attacker gained control of a legitimate, trusted publishing identity, then used that trust to push malicious code directly into the dependency tree of organizations that had done nothing wrong except run npm install.

Why Maintainer Accounts Are the Softest Target

Typosquatting and dependency confusion attacks require an attacker to trick a developer into typing the wrong package name, or to exploit a misconfigured internal registry. Those attacks are noisy, detectable, and increasingly well-defended against. Maintainer account takeover skips all of that friction. If an attacker controls the account that legitimately owns left-pad or chalk, they don't need to squat on a similar name or win a naming race — they can push a malicious version to the real package, under the real name, and every downstream project that has a loose version range (^, ~, or no lockfile discipline at all) will pull it automatically on the next install.

The attack surface on the account side is uncomfortably wide:

  • Credential phishing remains the dominant vector. The September 2025 chalk/debug compromise reportedly began with a phishing email impersonating npm support, warning the maintainer that two-factor authentication needed to be "updated" via a fake login page. It worked on one of the most experienced open source maintainers in the ecosystem — a reminder that technical skill does not correlate with phishing resistance.
  • Token leakage is a close second. Long-lived npm publish tokens stored in CI environment variables, shell history, or old .npmrc files get scraped from misconfigured public repos, leaked build logs, or compromised developer laptops, and then reused directly for publishing — no phishing required.
  • Account recovery abuse and weak or absent 2FA enforcement let attackers walk through password reset flows on abandoned or loosely monitored maintainer accounts, particularly for packages whose original authors have moved on but never transferred ownership.
  • Self-propagation is the newest wrinkle. The Shai-Hulud worm didn't stop at one package — once it had valid publish credentials, it enumerated every other package the compromised maintainer could push to, and in some documented cases attempted to harvest tokens from CI systems it landed in to jump to still more packages, turning a single credential compromise into a multi-hop worm.

The Blast Radius Problem

What makes this vector so disproportionately dangerous is the structure of the npm dependency graph itself. A package like debug or chalk is rarely a direct dependency of the applications that are ultimately affected — it's usually three, four, or five levels deep, pulled in transitively by a logging library, a CLI framework, or a build tool that a team depends on directly. Most organizations have no reliable inventory of what's actually in that transitive graph, let alone which of those transitive packages are wired into a code path that ever actually executes at runtime.

That gap is exactly why maintainer takeovers are so effective as an attack strategy and so hard to triage after the fact. When chalk was compromised, security teams everywhere faced the same two questions in the same order: "Do we even have this package anywhere in our environment?" and, if so, "Is the compromised code path something our application actually calls, or is it dead weight we can safely deprioritize while we patch?" For teams without a current SBOM and without any way to trace call paths from application entry points down into third-party code, both questions took hours or days to answer — time that, in an active incident with malicious code already published, is the difference between a contained event and a production compromise.

The Trust Model Hasn't Caught Up With the Stakes

npm has made real improvements — mandatory 2FA for maintainers of high-download packages, provenance attestations for packages published from trusted CI, and faster registry-side anomaly detection for unusual publish patterns. These are meaningful steps. But they are opt-in or partial by design, and adoption lags well behind the size of the ecosystem: millions of packages, many maintained by a single individual, with publish rights that, once granted, are rarely audited or rotated. The registry's trust model was built for an era when open source consumption was smaller and slower; it is now straining under an ecosystem where a compromised token can reach a billion weekly installs before anyone notices.

Postinstall scripts compound the problem. A malicious version doesn't need a developer to call a new function — many of these incidents deliver their payload the moment npm install runs, via lifecycle scripts that execute automatically and exfiltrate environment variables, cloud credentials, or CI secrets before a human ever looks at a diff.

What Security Teams Should Be Doing Right Now

Independent of any single vendor's tooling, there are concrete steps that materially reduce exposure to this class of attack:

  1. Pin dependencies and use lockfiles rigorously. Loose semver ranges are precisely what let a malicious patch version propagate silently across an entire fleet of builds overnight.
  2. Maintain a current, queryable SBOM. If you cannot answer "do we have chalk version 5.3.1 anywhere in our environment" within minutes of a disclosure, you are triaging blind.
  3. Restrict and audit lifecycle scripts. Disabling or sandboxing postinstall/preinstall execution for third-party packages closes off the fastest payload-delivery path attackers currently use.
  4. Monitor for anomalous publish activity on packages you depend on — sudden version bumps outside a maintainer's normal cadence, new maintainers added to a package, or provenance attestations that suddenly disappear.
  5. Rotate and scope your own CI/publish tokens so that a leak in one project can't cascade into publish rights on unrelated packages — the same discipline you'd want every upstream maintainer to practice too.

How Safeguard Helps

Safeguard is built for exactly this scenario: the moment a trusted package turns hostile, and the clock starts on figuring out whether you're exposed. Our SBOM generation and ingestion pipeline gives teams a continuously current inventory of every direct and transitive dependency, so when the next chalk-style compromise breaks, "are we affected?" is a lookup, not a fire drill. Reachability analysis then goes a step further, tracing whether the compromised code in a flagged package is actually invoked from your application's entry points — separating packages you need to patch immediately from ones you can safely schedule, so incident response effort goes where the real risk is. Griffin, Safeguard's AI security analyst, continuously watches for the signals that precede and accompany maintainer takeovers — anomalous publish patterns, newly added maintainers, sudden lifecycle-script changes, and known-malicious version fingerprints — and surfaces them before they reach your build. When a fix is available, Safeguard can open an auto-fix pull request that pins to a known-safe version and updates your lockfile automatically, cutting the time between disclosure and remediation from days to minutes. Together, these capabilities turn maintainer account takeover from an unpredictable ecosystem-wide emergency into a bounded, manageable event.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.