CrowdStrike npm Supply Chain Attack
If you thought 2025 was going to be a quiet year for supply chain security, September had other plans. Between September 14-18, the npm ecosystem experienced what security researchers are calling the most sophisticated supply chain attack to date – and yes, it even caught packages maintained by CrowdStrike in its net.
Let me walk you through what happened, why it matters, and what you need to check right now.
The Scale of the Problem
When I first heard about this attack, I thought it was another one of those “a dozen packages got compromised” situations we see every few months. Then I saw the numbers: 194 distinct packages, 582 compromised versions, and this thing was self-replicating like an actual worm.
@ctrl/tinycolor pulls 2.2 million downloads per week. ngx-bootstrap gets 300,000. These aren’t some obscure packages that only three people use – these are production dependencies running in thousands of applications right now.
And the irony? Twelve of CrowdStrike’s own development packages got caught in the attack. Yes, that CrowdStrike – the cybersecurity company. Before you laugh, remember that even security vendors maintain internal tooling packages, and this attack was sophisticated enough to compromise developer accounts regardless of who they work for.
How It Actually Worked
Here’s where things get interesting. The attackers didn’t just upload malicious packages. They created the first successful self-replicating worm in npm’s history.
Think about how a worm spreads: it infects one machine, then uses that foothold to spread to others, which spread to others, creating exponential growth. That’s exactly what happened here, except instead of computers, it was npm packages.
The attack chain went like this:
- You run
npm installon a compromised package - A postinstall hook runs a 3.6MB file called
bundle.js - That script steals your npm credentials from your system
- It queries the npm registry to find the 20 most popular packages you maintain
- It downloads those packages, injects itself into them, and publishes new versions
- Anyone who installs those packages repeats the cycle
Each victim became a vector for spreading to more victims. Elegant in its simplicity, terrifying in its effectiveness.
What the Malware Actually Stole
The payload, nicknamed “Shai-Hulud” (a Dune reference – even attackers are nerds), wasn’t subtle about what it wanted. When that bundle.js file executed, it went after everything:
Your Credentials
First up: credential harvesting. The malware grabbed every environment variable it could find – NPM_TOKEN, GITHUB_TOKEN, AWS keys, GCP credentials, Azure service principals. If you had it in your environment, it got copied.
But it didn’t stop there. The attackers cleverly downloaded and executed TruffleHog, a legitimate open-source secret scanning tool, to scan your entire filesystem for high-entropy strings that might be secrets. Then it validated those credentials by actually testing them against the real APIs. It checked if npm tokens were valid by running npm whoami, tested AWS keys by calling AWS STS, and so on.
And if you were running this in a cloud environment? It queried cloud metadata services to grab ephemeral credentials and then used those to pull secrets from AWS Secrets Manager, Google Cloud Secret Manager, and Azure Key Vault. This wasn’t some script kiddie operation.
Your GitHub Repos
The GitHub attack vector was particularly nasty. The malware created a new branch called shai-hulud in your repositories and added a GitHub Actions workflow that would trigger on every push and exfiltrate all your repository secrets to an external webhook.
But here’s the kicker: it also ran a script that converted your private organization repositories to public personal repositories, appending “-migration” to the names and adding a description of “Shai-Hulud Migration.” Over 700 private repos were exposed this way before the attack was discovered.
Data Exfiltration
The stolen data went to two places:
- A public GitHub repository named “Shai-Hulud” created under the victim’s own account, containing a triple base64-encoded
data.jsonfile with everything the malware collected - A webhook endpoint that received double base64-encoded data (which got so overwhelmed it hit its 100-callback limit and stopped working)
GitGuardian eventually detected 278 exposed secrets in the wild – 90 from local systems and 188 from compromised GitHub Actions workflows.
The Timeline
The attack unfolded over five days in mid-September 2025:
September 14: It started quietly – fewer than a dozen packages compromised, likely the attackers testing their approach.
September 15: All hell breaks loose. At 4:58 AM UTC, the first major batch of malicious packages hit the registry. By 10:41 AM, over 100 packages had been compromised in coordinated bursts. The attackers even released a new variant of the malware midday (you can tell by a different SHA-256 hash). By day’s end, about 50 malicious versions were live on npm.
September 16: The CrowdStrike packages get hit. The attack crosses 180 distinct packages. Socket.dev publishes the first public analysis of what’s happening.
September 17: The worm is fully active now, spreading exponentially. Security firms coordinate responses. Palo Alto’s Unit 42 team publishes their analysis.
September 18: The total exceeds 500 compromised versions. npm begins emergency takedowns across the registry.
September 23: CISA issues an official alert. By this point, all reported malicious versions have been removed from the registry – though the worm might still be active in any environment where stolen credentials haven’t been rotated.
What You Need to Do Right Now
If you’re reading this thinking “I’ll check later,” stop. Here’s what you need to do immediately:
1. Check if you’re affected
Search your package-lock.json for any of the compromised packages. The complete list is at the end of this post. Pay special attention to:
- Anything from
@crowdstrike/* @ctrl/tinycolor,ngx-bootstrap,ng2-file-upload,angulartics2- The
@nativescript-community/*,@operato/*, and@ctrl/*namespaces
If you find any matches, compare the installed version numbers against the compromised versions list.
2. Look for signs of infection
Quick checks you can do right now:
- Search your node_modules for any 3.6-3.7MB
bundle.jsfiles in package root directories (not in subdirectories) - Check your GitHub account for any repository named “Shai-Hulud”
- Look for branches named
shai-huludin your repos - Search for
.github/workflows/shai-hulud-workflow.ymlfiles - Check if any private repos mysteriously became public with a “-migration” suffix
3. If you’re compromised, act fast
This is not the time to be thorough first and fast second. If you found any of the above:
Rotate every credential that might have been on that system:
- npm access tokens (delete and regenerate, don’t just rotate)
- GitHub Personal Access Tokens
- AWS credentials (keys, secrets, session tokens)
- GCP service account keys
- Azure service principals
- SSH private keys
- Every API key in your environment variables
I know this sounds extreme, but remember: the malware ran TruffleHog against your entire filesystem. If it was there, it’s compromised.
Check your cloud logs:
- AWS CloudTrail for unusual API calls
- GCP audit logs for unexpected secret access
- Azure Activity logs for unauthorized operations
Audit your npm publishes: If you maintain packages, check your publish history on npm for versions you didn’t release.
4. Prevention for next time
Once you’ve cleaned up, lock things down:
- Pin your dependencies. Use exact version numbers, not version ranges. Yes, it’s more maintenance. No, it’s not optional anymore.
- Enable 2FA on npm for package publishing. Make it phishing-resistant if possible.
- Add security scanning to your CI/CD pipeline. Tools like
npm audit, Socket.dev, or Snyk should run on every build. - Wait before upgrading. Give new package versions a few days to cook before adopting them. If everyone did this, the worm would have spread much slower.
- Use the principle of least privilege. Your build agent doesn’t need AWS admin credentials. Your laptop doesn’t need to write to production npm packages.
The CrowdStrike Response
CrowdStrike issued a statement clarifying that their Falcon endpoint security product was not compromised. Only internal development and tooling packages – the kind developers at CrowdStrike use for their own work – were affected. Customers remained protected.
They quickly removed the compromised packages and rotated all their keys. It’s a reminder that even security companies aren’t immune to supply chain attacks when the attack vector is developer tooling itself.
Why This Matters
This wasn’t just another supply chain attack. This was the first self-replicating worm in npm’s history. The sophistication here is worth noting:
- It used legitimate tools (TruffleHog) instead of custom credential-stealing code, making it harder to detect
- It weaponized GitHub Actions, turning your CI/CD pipeline into an exfiltration channel
- It targeted cloud-native secrets, not just local files
- It spread automatically, turning each victim into a new attack vector
CISA called it a “widespread supply chain compromise.” Palo Alto’s Unit 42 labeled it “the most severe JavaScript supply chain attack observed to date.” They’re not wrong.
The Bigger Picture
Supply chain attacks have been evolving. We went from typosquatting (registering cross-env to catch people who typo crossenv) to account compromises (stealing a maintainer’s credentials) to dependency confusion (uploading malicious internal package names to public registries).
Now we have worms that spread automatically through the ecosystem itself.
The npm ecosystem has always operated on trust. We trust that package maintainers aren’t malicious. We trust that their credentials are secure. We trust that their development machines are clean. This attack exploited every layer of that trust simultaneously.
The uncomfortable truth is that when you run npm install, you’re executing code from dozens (sometimes hundreds) of developers you’ve never met, on systems you can’t inspect, through a supply chain you can’t verify. This attack made that risk painfully concrete.
Where to Learn More
If you want the deep technical details, several security firms published excellent analyses:
- Socket.dev’s initial disclosure
- Palo Alto Unit 42’s technical breakdown
- CISA’s official advisory (September 23, 2025)
- Reports from Endor Labs, Wiz Security, Snyk, GitGuardian, and OX Security
Appendix: Complete Package and Version Lists
For reference, here are all the compromised packages and their affected versions. Use these for auditing your package-lock.json files:
CrowdStrike Packages
| Package | Compromised Versions |
|---|---|
| @crowdstrike/commitlint | 8.1.1, 8.1.2 |
| @crowdstrike/falcon-shoelace | 0.4.1, 0.4.2 |
| @crowdstrike/foundry-js | 0.19.1, 0.19.2 |
| @crowdstrike/glide-core | 0.34.2, 0.34.3 |
| @crowdstrike/logscale-dashboard | 1.205.1, 1.205.2 |
| @crowdstrike/logscale-file-editor | 1.205.1, 1.205.2 |
| @crowdstrike/logscale-parser-edit | 1.205.1, 1.205.2 |
| @crowdstrike/logscale-search | 1.205.1, 1.205.2 |
| @crowdstrike/tailwind-toucan-base | 5.0.1, 5.0.2 |
| eslint-config-crowdstrike | 11.0.2, 11.0.3 |
| eslint-config-crowdstrike-node | 4.0.3, 4.0.4 |
| remark-preset-lint-crowdstrike | 4.0.1, 4.0.2 |
High-Profile Packages (millions of weekly downloads)
| Package | Compromised Versions | Weekly Downloads |
|---|---|---|
| @ctrl/tinycolor | 4.1.1, 4.1.2 | 2.2 million |
| ngx-bootstrap | 18.1.4, 19.0.3, 19.0.4, 20.0.3-20.0.6 | 300,000 |
| ng2-file-upload | 7.0.2, 7.0.3, 8.0.1-8.0.3, 9.0.1 | 100,000 |
| angulartics2 | 14.1.1, 14.1.2 | - |
Other Compromised Package Namespaces
The attack also hit 100+ more packages in these namespaces:
@ctrl/*(14 packages)@nativescript-community/*(25 packages)@operato/*(14 packages)@ahmedhfarag/*,@art-ws/*,@hestjs/*,@nexe/*,@nstudio/*,@teselagen/*,@things-factory/*,@tnf-dev/*,@yoobic/*
Total: 194 distinct packages, 582 compromised versions
For the complete detailed version list of all packages, check the security advisories from Socket.dev, CISA, or your preferred security scanning tool.
Related Reading:
When building and deploying your own tools, security should be a primary concern. If you’re interested in self-hosted solutions and automation tools with proper security considerations, check out:
- Asana to Gitea Migration Tool - A production-ready TypeScript tool with comprehensive testing and security best practices
- Trilium MCP Server - Self-hosted AI integration with proper authentication and security
- Roast My CV - Building a secure micro-SaaS with N8N workflows, handling sensitive data with proper privacy measures