All posts

Why npm audit and Snyk Miss 100% of Supply Chain Attacks

Run npm audit on the Axios compromise. Clean. Run it on Shai-Hulud, the first self-replicating npm worm. Clean. chalk/debug, 2.6 billion weekly downloads? Clean.

Every major supply chain attack in the past year passed npm audit without a flag. Not because the tool is broken. Because it was never built to catch them.

npm audit answers the wrong question

npm audit checks your dependency tree against an advisory database. So does Snyk. So does Dependabot. Someone discovers a vulnerability, files a CVE, and once it's in the database, these tools find it. They're good at this. No complaints.

A supply chain attack doesn't work that way. An attacker steals a maintainer's credentials, publishes a new version with a credential stealer or a RAT baked in, and waits. There's no bug to discover. The code does exactly what the attacker intended. No CVE gets filed because nobody knows it happened yet.

npm audit checks the database. The database has nothing. found 0 vulnerabilities.

The Shai-Hulud worm's first wave hit in September 2025 and compromised 180+ packages before anyone noticed. Its second wave, two months later, infected 796 packages in 72 hours through stolen npm tokens, including libraries from CrowdStrike, Zapier, and PostHog. From the registry's perspective, each compromised version was a normal publish by an authorized account. Nothing to flag. Asking npm audit to catch that is like asking a spell checker to detect misinformation. The tool works perfectly. It's answering a different question.

What behavioral scanning catches

The signal is in the code itself. Malicious packages do things legitimate packages don't do. Axios doesn't need to install a remote access trojan. Chalk doesn't need to hook fetch and rewrite cryptocurrency addresses. A worm that reads your .npmrc and republishes packages under your name looks nothing like a color library.

Dependency Guardian scans what the code actually does. Dozens of behavioral detectors, each targeting a specific attack pattern observed in real-world npm and PyPI malware: install scripts that drop executables, outbound connections to hardcoded IPs, credential file reads, obfuscation layers built to dodge inspection, typosquatted package names, suspicious changes between versions.

None of this needs an advisory to exist first. The scanner reads the code and flags what's suspicious, the same way you would if you had time to audit every line of every dependency you pull in. You don't. Nobody does.

This isn't hypothetical

When we caught ahmed_salem_ph, a trojanized AI coding assistant hiding a Windows keylogger, the package had been on npm for less than 30 minutes. No CVE. Only 3 of 76 antivirus engines on VirusTotal flagged the binary. No advisory anywhere.

Dependency Guardian scored it 100 out of 100. The detectors fired on a hidden executable, obfuscated JavaScript, and PowerShell running with -WindowStyle Hidden. Every signal pointed the same direction.

Socket had indexed it too. Their score: 65, not classified as malware. The malicious signals were present in their data, but diluted by composite scoring that averaged in license and maintenance metrics. A trojan with a clean MIT license and a fresh publish date doesn't trip a composite score the way it should. That's the difference between reading behavior and averaging categories.

Run both

npm audit handles known vulnerabilities. It automates patching. Keep running it.

But it can't catch the next Axios, the next Shai-Hulud, the next chalk hijack. Those attacks don't have CVEs while they're live. By the time an advisory exists, the damage is done.

Dependency Guardian catches malicious code that nobody has reported yet. Install it alongside what you already run.

npm install -g @westbayberry/dg

Or install the GitHub App to scan every PR that touches your dependencies. Free tier, 1,000 scans per month, all detectors. No credit card.