TL;DR
Malicious npm packages are not an occasional event. They are a continuous publishing operation, and the list of confirmed cases updates every week. Across seven consecutive editions of our Malicious Code Digest, now past its 87th, Xygeni confirmed 635 malicious packages, from 13 in a quiet week to 206 in a busy one. The weekly range is the point: this is a cadence, not an incident.
- The cadence is the problem. One package went from zero to more than 55 versions in a week. Another cluster published nearly 30 package names in under three hours. A weekly audit is the wrong unit of time.
- They do not arrive as CVEs. A malicious package is not a flaw in legitimate code, so there is no advisory, no score and usually no identifier at all. A vulnerability-driven programme is structurally blind to this.
- Takedown is not protection. Packages are typically live for minutes to hours. Your install either happened in that window or it did not.
- Detection has to sit at publication, and enforcement at install. Anything that waits for a signature, a CVE or a weekly scan arrives after the build that pulled it.
The List Exists. That Is Not the Same as Being Watched
There is no mystery about malicious npm packages. Confirmed cases are published, named, and documented every week, including in Xygeni’s own Malicious Code Digest, now past its eighty-seventh edition.
The gap is not information. It is attention and cadence. A list updated weekly, read monthly, and acted on quarterly is a list that documents what already happened to somebody.
Here is what seven weeks looked like, taken from our own confirmed findings rather than from a vendor survey.
| Digest | Confirmed packages | What stood out |
|---|---|---|
| Digest 87 | 13 | First Composer cluster. @umschool/platform published at 999.0.0 to outrank an internal package |
| Digest 86 | 35 | Baileys campaign rotates aliases. Four @stellarshift packages published at an identical version |
| Digest 85 | 53 | [confirm standout] |
| Digest 84 | 34 | Baileys impersonation across four names and six days. cloud-baileys republished four times |
| Digest 83 | 114 | wormgpt-cli: nine versions in a single day, named after a real dark-LLM tool |
| Digest 82 | 206 | [confirm standout] |
| Digest 81 | 180 | 17 packages impersonating internal PayPal names at 28.0.0. zevairouter past 55 versions |
The pattern that matters is not the totals. It is the speed inside each week.
Speed Is the Whole Attack
Three findings from those weeks, each one a different way of outrunning review.
- Version flooding. A single npm package,
zevairouter, reached more than 55 confirmed versions in one week, joined by ten more from a companion package. On PyPI,bingo-aiproduced nearly 80 versions in roughly 30 minutes. No manual review process operates at that speed, and neither does a nightly job. - Synchronised clusters. Seventeen packages impersonating internal PayPal service names were published within the same few minutes, all at version 28.0.0. That is not volume, it is a race: an inflated version number exists to outrank the internal package your own teams wrote. The same trick reappeared weeks later with
@umschool/platformpublished at 999.0.0. - Persistence through takedown. The Baileys impersonation campaign has been running for weeks. Names rotate, versions climb, republication continues after detection. An operator who treats takedowns as a cost of doing business rather than a reason to stop is an operator your once-a-quarter review will never catch up with.
And the dwell time is short by design. In one recent cluster, the packages were live for between 17 minutes and 13 hours before removal.
| Package | Published (UTC) | Left standing |
|---|---|---|
moidev | 2026-08-16 16:31 | 5h 58m |
moidevx | 2026-08-17 03:24 | 13h 23m |
moidevz | 2026-08-26 03:38 | 12h 56m |
moideva | 2026-08-26 18:58 | 1h 33m |
amicat | 2026-08-28 20:48 | 17m |
bmcat | 2026-08-28 21:17 | 47m |
eyevox | 2026-08-28 21:44 | 21m |
moidevh | 2026-08-31 03:22 | 47m |
Read that as an exposure window rather than a performance metric for the registry. If a build ran during it, the takedown changed nothing.
Why Your Vulnerability Programme Does Not See This
This is the structural point, and it is the one most security teams have not internalised.
| A vulnerability | A malicious package | |
|---|---|---|
| Origin | A mistake in code written in good faith | An artifact built and published to cause harm |
| Identifier | CVE, with an advisory and a score | Usually none. No CVE, no advisory |
| Timeline | Disclosed, then patched over days or weeks | Live for minutes to hours, then removed |
| How you learn | Feed, scanner, advisory | Only if something was watching the registry at publication |
| The fix | Upgrade to a patched version | There is no patched version. It was never legitimate |
| What your programme does | Ingests, scores, schedules | Nothing, unless it was built for this |
A vulnerability is a flaw in code somebody wrote in good faith. A malicious package is a deliberate artifact published by an attacker, usually with no identifier, no advisory, and a lifespan measured in hours. Every process built around CVE ingestion, severity scoring and patch windows was designed for the first thing and applied to the second by default.
The absence of an identifier is not an oversight in the CVE system. It is the category working as designed: nobody files an advisory against an artifact whose entire purpose was malicious, and by the time anyone could, the package is gone. Which means the question “does this have a CVE” returns the same answer for a clean package and for a credential stealer published an hour ago.
What the Payloads Actually Do Now
The naive picture of malicious npm packages is a crypto miner. The current reality is credential theft aimed at developers, and increasingly at the AI credentials on their machines.
The PhantomSync cluster, eight npm packages published under one account, worked exactly as advertised while hiding a self-invoking dropper that fired roughly 37 seconds after import, decoded a payload staged as a fake test fixture, installed cross-platform persistence, and launched a wallet and secrets stealer. Delay, disguise, persist, exfiltrate.
At larger scale, the CHAINDROP wave of the Shai-Hulud worm hit more than 400 packages and 1,700 versions in early August 2026, with a combined 1.3 billion monthly downloads. Its collector scanned for more than 300 credential patterns, including OpenAI, Anthropic and Cursor keys. Developer machines became valuable precisely because of the model credentials sitting on them.
Naming conventions have followed the money. Recent clusters impersonate crypto and DeFi SDKs, payment modules, WhatsApp API libraries, AWS utilities and, in one case, a package openly branded after a dark-LLM attacker tool.
What Actually Stops Malicious npm Packages
Four controls, in the order they pay off.
1. Detection at publication, not at disclosure. Xygeni’s Malware Early Warning analyses newly published packages across npm, PyPI, Maven, and other registries at the moment they appear, using behavioural and anomaly analysis rather than waiting for a signature or a report. That is the only point in the timeline that is ahead of your build.
2. Enforcement where the install happens. Detection tells you a package is malicious. A policy that blocks the install is what prevents the postinstall script from running. This matters more now that agents install dependencies without a human choosing them.
3. Lockfiles and hash pinning. Use npm ci in CI rather than npm install, so the exact dependency tree in the lockfile is what gets built. It closes the substitution route that typosquats and inflated versions rely on.
4. Findings in one place. Malware findings belong in the same prioritised queue as your SCA and code findings, not in a separate feed somebody skims. A confirmed malicious dependency should outrank a medium-severity CVE, and only a shared risk model makes that comparison possible.
Watch the List, or Automate It
Nobody has the attention to read a registry feed every week. That is the point of automating it.
Xygeni analyses newly published packages across npm and other registries at the moment of publication, flags confirmed malware before it reaches a build, and puts the finding in the same prioritised queue as everything else your teams already work from. Malware detection is included in the free Developer plan, which is not true of most free tiers in this category.
Start free, or read this week’s Malicious Code Digest first.
FAQ
What are malicious npm packages?
Packages published to the npm registry that are deliberately built to cause harm: credential and wallet stealers, backdoors, droppers, and dependency-confusion artifacts that impersonate internal or popular package names.
How common are malicious npm packages?
Continuously. Across seven recent editions of our Malicious Code Digest, Xygeni confirmed 635 malicious packages, ranging from roughly a dozen in a quiet week to over 200 during active campaigns. npm accounts for the overwhelming majority.
How long do malicious npm packages stay available?
Often minutes to hours. That window is what matters, because a build running inside it is already affected regardless of how quickly the package is removed afterwards.
Do malicious npm packages get CVEs?
Usually not. They are attacker-published artifacts rather than flaws in legitimate code, and tracked 2026 campaigns received no CVE assignments during active exploitation.
How do I check if a package is malicious before installing?
Use a tool that analyses packages at publication rather than one that checks a known-bad list, verify the publisher and version history, be suspicious of unusually high version numbers and brand-new accounts, and enforce a policy at install time rather than relying on review.
What is dependency confusion?
Publishing a public package with the same name as an internal one, usually at an inflated version, so the resolver prefers the attacker’s copy. The PayPal-name cluster at version 28.0.0 is a textbook example.







