Key Takeaways
- CI hijack is the most dangerous vector for top-100 packages, while typosquatting dominates the mid-tier where fewer eyes spot malicious code.
- Token theft is the stealthiest option, giving attackers long-lived access that bypasses registry security entirely.
- Your defense strategy should change based on which tier your dependencies live in, not one-size-fits-all tooling.
If you manage a codebase, you already know the drill. You run npm install, the build passes, and everything ships. But what if the package you pulled was not actually what it claimed to be? What if the entry point into your supply chain was not a clever exploit at all, but something far simpler.
Here is the uncomfortable truth most security teams skip. Attackers pick their entry vector based on one thing, the popularity tier of their target package. A top-100 dependency with millions of weekly downloads faces a completely different attack landscape than a niche package with barely any traction. And your defense should reflect that difference.
In this post, we are going to break down four major attack vectors, CI hijack, token theft, typosquatting, and worm-style propagation, and map them against package popularity tiers. By the end, you will know exactly where your risk is concentrated and what to prioritize.
The Four Vectors, Explained
Before we compare them, let us make sure we are all on the same page about what each vector actually looks like in the wild.
CI Hijack
This is where an attacker compromises your CI/CD pipeline configuration rather than the source code itself. They do not need write access to your repository. They need write access to your pipeline settings, your deployment tokens, or your build artifacts. Think of the CI/CD security angle here, because that is exactly where the gap lives.
How it plays out. An attacker finds a misconfigured webhook on a popular npm package repository. They inject a malicious script into the build pipeline that exfiltrates secrets or publishes a compromised version. The package itself looks fine in the source code. The poison is in the pipeline output.
Token Theft
Token theft is about stealing published access credentials, GitHub tokens, npm access tokens, CI service tokens, or deployment keys. Once an attacker has a valid token, they do not need to break into anything. They just use what they already hold.
This is the vector behind some of the most damaging supply chain compromises in recent memory. The March 2021 npm registry incident, where attackers created two legitimate-looking packages, was enabled by compromised maintainer accounts. The token was the real vulnerability, not the package content itself. Read our analysis on crypto org supply chain losses for a deeper look at how this plays out in practice.
Typosquatting
This one is almost embarrassingly simple. An attacker publishes a package with a name that closely resembles a popular one. react-router-dom becomes react-router-dom-fix. lodash becomes lodahs. One missing letter. One swapped character. And developers installing it without a second thought.
The beauty of typosquatting for an attacker is that it requires zero access to the real package. No compromised account. No stolen token. No CI access. Just a similarly named package and a postinstall script that does whatever the attacker wants.
Worm-Style Propagation
Worm-style attacks are different from the other three because they do not rely on a single compromised package. Instead, they use one foothold to automatically spread to related packages. The classic pattern, an attacker compromises one low-tier package, then uses published access tokens to push malicious updates to a network of related packages they also maintain. The compounding effect turns a single entry point into dozens of compromised dependencies overnight.
We have seen this pattern in the wild with npm supply chain campaigns, and it is exactly the kind of attack that makes package-lock.json integrity such a critical topic for teams running monorepos.
The Framework: Why Package Tier Matters
Here is the insight most teams miss. The effectiveness of each attack vector is not constant across all packages. It flips depending on how popular the target is.
We can divide the npm ecosystem into three tiers:
- Top-100 packages, the ones with millions of weekly downloads and a maintainer community that reviews every change.
- Mid-tier packages, somewhere between 10,000 and 500,000 weekly downloads, with active maintainers but limited eyeballs.
- Niche packages, below 10,000 weekly downloads, often maintained by a single person who may not even be security-aware.
Let us walk through what happens to each vector at every tier.
Top-100 Packages
These packages are heavily watched. Maintainers enforce two-factor authentication. Access tokens are scoped tightly. The community patches vulnerabilities within hours, not days. So which vector actually works here?
CI hijack dominates. Going after the source code is nearly impossible. But the CI pipeline that builds and publishes the package, that often has weaker controls. A compromised GitHub Actions workflow, a stolen deployment token, a misconfigured npm publish script, those are the real attack surfaces.
For top-100 packages, token theft is the second most effective vector, but it requires high-skill operations. You are not just stealing a token. You are stealing one that has publish access to a package millions of people depend on. That level of access is hard to obtain.
Typosquatting barely matters here. Nobody is going to install reacr instead of react when the real thing is this widely used. The typo is too obvious, and the community catches it immediately.
Worm propagation is rare but devastating when it happens. A single worm in a top-100 package can cascade into the entire ecosystem because so many downstream dependencies pull from it.
Mid-Tier Packages
This is where the attack landscape changes dramatically. Mid-tier packages have enough visibility that random noise gets filtered out, but not enough that every commit gets scrutinized. They sit in the danger zone.
Typosquatting becomes a major threat here. A mid-tier package might have a name like date-fns or axios. There is room for plausible typos, and the maintainers simply do not have the bandwidth to monitor every similar name. The attacker publishes date-fns-v3 or axiós and waits for someone to install it.
CI hijack remains a real risk. Many mid-tier teams run CI on shared platforms with configuration that is not as hardened as top-tier projects. The maintainers are often individuals, not security teams.
Token theft is the sweet spot for attacker effort versus reward. A mid-tier package token gives you access to a package with real adoption, but the maintainer may not have rotated their credentials recently. The token theft to impact ratio is favorable.
Worm propagation starts becoming viable. If an attacker controls a few mid-tier packages that share a dependency graph, they can use one compromise to influence many downstream builds.
Niche Packages
Here is where things get quiet, and that is exactly what makes it dangerous. Niche packages fly under everyone radar. No automated scanners flag them. No community watches for changes. And yet, your application probably depends on three or four of them.
Typosquatting is the most common vector here. The barrier to entry is near zero. Publish a package with a similar name, add a postinstall crypto miner or data exfiltrator, and move on. The chance of anyone noticing is slim.
Token theft is straightforward. Niche maintainers often reuse tokens across projects. They may not enable MFA. Their tokens may have broader permissions than necessary. The security posture gap between top-100 and niche packages is staggering.
CI hijack is less relevant because many niche packages do not even have CI pipelines. But when they do, the security is typically minimal or nonexistent.
Worm propagation is surprisingly effective in this tier. Because niche packages are so numerous and so loosely monitored, a worm that targets the dependency graph can spread through hundreds of packages before anyone raises an alarm.
The Comparison Matrix
Let us pull this together into a single reference. The matrix below shows relative effectiveness for each vector at each tier.
| Vector | Top-100 Tier | Mid-Tier | Niche Tier |
|---|---|---|---|
| CI Hijack | HIGH | HIGH | LOW |
| Token Theft | MEDIUM | HIGH | HIGH |
| Typosquatting | LOW | HIGH | HIGH |
| Worm Propagation | MEDIUM | HIGH | HIGH |
Notice the pattern. As packages get less popular, the attacker has more options, and the barriers to entry drop significantly. But here is the thing most teams get wrong. They treat all their dependencies as if they are top-100 packages, when in reality the bulk of their supply chain risk lives in the mid-tier and niche.
Building Your Defense Strategy
So what do you actually do with this information? Here is the practical framework I recommend.
Step 1: Map Your Dependency Profile
Run an audit of every package your application depends on. Categorize each one by its weekly download count. Are your critical path dependencies in the top-100, or are they scattered across the mid-tier and niche? The answer will determine where you focus your attention.
Step 2: Tier Your Defenses
For top-100 packages, focus on CI pipeline hardening. Enforce branch protection rules. Require PR reviews for any .github/workflows/ changes. Use signed commits and lockfile integrity verification that CI enforces strictly. Rotate your CI tokens on a schedule.
For mid-tier packages, add typosquatting detection to your build pipeline. Tools like npm audit catch some of this, but dedicated typosquatting detection scanning goes further. Check package provenance using npm provenance attestation when available. Monitor your dependency graph for any package that suddenly gains maintainers or changes its postinstall scripts.
For niche packages, the best defense is minimization. Audit what you actually need. Each niche dependency is a potential entry point. Consider replacing niche packages with more established alternatives. Where replacement is not possible, run isolated builds and scan artifacts before they reach production.
Step 3: Implement a Lockfile-First Pipeline
This is non-negotiable. Your CI should never run npm install without a committed package-lock.json. Use npm ci exclusively in your build environment. This eliminates the window where a malicious package could be published between when a developer commits their lockfile and when the build runs.
Combine this with lockfile integrity checks that verify the integrity hashes match exactly what is published. Any deviation should fail the build immediately.
Step 4: Token Hygiene
Use scoped tokens with the minimum permissions required. A publish-only token should not have read access to your repository. A deployment token should not have access to your npm publish registry. Rotate these tokens regularly and audit who has access to them.
If an attacker steals a token, you want it to be useless beyond a very narrow scope. This is the same principle behind credential compromise recovery procedures, applied proactively rather than reactively.
Step 5: Watch for Worm Patterns
The worm propagation vector is the one most teams overlook. Set up alerts for any package in your dependency tree that suddenly has a new postinstall or prepublishOnly script. Monitor for packages that change maintainers unexpectedly. If a package you depend on starts depending on packages you have never heard of, investigate immediately.
Internal Links for Deeper Dives
- The Supply Chain Attack Lurking in Your Trusted Software Downloads, which walks through a real-world npm compromise scenario.
- Seven package-lock.json Integrity Bypass Moves, a detailed look at how lockfiles can be subverted and how to prevent it.
- Your package-lock.json Integrity Is a Polite Suggestion Until You Do This, the practical guide to making lockfile verification actually enforceable in your CI.
FAQ
Which attack vector is the most common in the npm ecosystem?
Typosquatting is the most frequent by volume, especially in the mid-tier and niche. CI hijack and token theft are less common but cause far more damage per incident because they target packages with higher exposure.
Does npm audit catch typosquatting attacks?
Not reliably. npm audit checks for known vulnerabilities in published packages. It does not compare package names for similarity. You need dedicated typosquatting detection tools for that layer of protection.
How can I tell if my CI pipeline has been hijacked?
Look for unexpected changes in your workflow files, unauthorized secret rotations, build artifacts that do not match your source code, and any new dependencies added to your package-lock.json without a corresponding commit. Compromise detection practices from incident response play a role here too.
Should I audit my niche dependencies as carefully as my top-tier ones?
Yes, but the approach should be different. Top-100 packages need CI and token hardening. Niche packages need a minimization strategy. If a niche package can be replaced, replace it. If not, verify its integrity hashes and monitor it closely for unexpected changes.


