Keyv and friends compromised in active Shai-Hulud supply chain attack
209 points - today at 11:01 AM
SourceComments
It's time pre-install / post-install hooks were killed off. Start with a moratorium on any new ones.
It sucks that we have this glass-jaw dependency system, which is really the main reason these supply chain attacks work.
Really hard to clean up, too. These days, you (being the blackhat) would likely send agents to leverage every compromised repo/app/Web site, almost the instant it comes online, so even if the original mess is cleaned up, there's still a ton of knock-on compromises.
This should be your default minimum if you work with node.
1. NPM Supply Chain Attack Techniques: https://npm-supply-chain-attack-techniques.pagey.site/
2. NPM Ecosystem Threat Report: https://npm-supply-chain-attacks-25-26.pagey.site/
I also wrote an article (https://evertheylen.eu/p/shame-devs-without-isolation/) to flesh out my thoughts, but I'd be really happy to discuss this in the comments.
Surely Github's software is good enough that an intern can slop the 80/20 together in a day? It would be an actually good use of AI spending.
Unless...
Maybe in 6 months.
How many instances of this are required before npm package maintainers learn?
Some additional detail from our analysis:
1. Provenance did not fail, it worked as designed and still shipped malware. The initial 11 packages were published through npm OIDC Trusted Publishing with valid SLSA attestations. The attacker compromised the maintainer's GitHub account and let the projects' own release workflows publish. Provenance proves which commit was built, not that the commit was authorized.
2. There is a booby trap on remediation: the worm installs a watcher that fires an attacker payload when the stolen GitHub token gets revoked. Remove the token monitor first, then rotate.
3. Persistence goes beyond node_modules. It writes .claude/settings.json (SessionStart hook) and .vscode/tasks.json (runOn: folderOpen), each re-executing the dropper. Check repo dotfiles too.
4. No C2 domain to sinkhole: exfil endpoints resolve at runtime from an Ethereum contract. Observed domain is npm-cache.com, but the operator can rotate it and push new code to infected hosts.
If you're auditing: look for setup.mjs, a 727,680 byte Math_Symbol.js (math_init.js in the second wave), and "preinstall": "node setup.mjs" in package.json. Careful, regenerate-unicode-properties ships a legitimate 1 KB Math_Symbol.js; the malicious one is over 700 KB.
Full IOC and package list in the post, updated as the campaign develops.
Combine that with the workflow split insanitybit describes — build/test jobs holding zero publish credentials, a separate publish job that only touches a finished artifact — and the wormable path is mostly closed without waiting for npm to redesign itself.
None of this is "sufficient" in rcxdude's sense, and that's fine. Sufficiency isn't the bar during an active outbreak; raising the attacker's cost per hop is.
To the point of the article: I don't know why GitHub still allows the release feature. It is complete insanity. Tar archives must be constructed manually and checked for leaked keys etc.
Like in the good ole days of Windows 98 and antivirus era, a lot of advanced virus techniques in the wild came from the people who used to work for AV companies
This is such lazy or click baiting writing. Who cares how many installations there are per month normally? The high install numbers are almost certainly from running in CI where such secrets don’t exist. How many installs actually occur in a non CI environment and of those how many were the compromised version?