Hello internet,
Do you remember the Shai-Hulud attack that hit @AntV on May 19th, 2026? I know, it feels like a lifetime ago by now in the supply chain world. A compromised maintainer account pushed 639 malicious versions of @antv packages to npm in a single hour. We, along with most of the npm security community, tore that payload apart within hours. It was nothing novel, technique-wise. It was just another day of waking up and there being a supply chain attack. Business as usual.
Since then, npm has introduced publish-time malware scanning. So you can imagine my surprise when I was going through our triage queue this morning and saw what I immediately recognized as a wormy boy. It had the same hash as the @AntV wave. Same payload:
e37e3ddeeaaa9e0c4fdbcb829b4895a6521031c80053fc436625b61e6ee5b1a6. This is the identical file that npm, us, and half the vendors on this list had already fingerprinted months ago.
That's 111 days of complete silence on that hash. As far as we can tell, that's the longest dormancy-to-reactivation gap we've seen from a Shai-Hulud payload, and it's not close. Call it what it is: a zombie, surfacing four months after everyone assumed it was dead.
The four packages that brought it back, all published within the same hour on September 7 by the same npm account:
feishu-docx-mcp@0.3.2bmc-i18n-extract-cli@1.1.1blueai-cli@0.7.0bmc-translate-utils@1.1.1
The numbers
We pulled our detection history for this exact file hash across every package release we've scanned. Here's what the timeline actually looks like:
Our records show 319 package versions carrying this hash, every single one of them first seen on May 19, 2026, the day of the @AntV wave and not a day before or after it. Then nothing. Zero new hits on this hash between May 20 and September 6. Then, starting today (September 7), four more package versions landed on npm carrying the exact same payload. That's a 111-day gap: last seen May 19, next seen September 7.
Four packages is a small number attached to a larger fact: a payload with a known, published, indexed hash sat untouched in nobody's toolchain for over three months and was then republished on a registry that, as of this year, explicitly scans every package before it goes live.
The easy case
In July, npm rolled out publish-time malware scanning: every package gets held for 5 to 15 minutes while an automated system checks it before it becomes installable. Per npm's own changelog, the goal is to catch "the malware we can detect" before it reaches npm install.
A file hash match is a lookup, not a hard problem. It requires no behavioral analysis, sandboxing, or reasoning about obfuscated code’s intent. And this payload wasn't novel, repacked, or even lightly modified to dodge signature matching. It was the same 64 hex characters that had been on file since May.
We're not saying the scanner should catch everything. The likes of multi-stage loaders, dependency confusion, and runtime-triggered payloads are genuinely hard problems. An exact hash match to a worm that made international security news four months ago isn't, though. That's the floor of what publish-time scanning is supposed to catch, and it got missed. This specific sample should be in the testing corpus of anybody doing supply chain scanning.
The takeaway
A worm payload with a public hash, extensive vendor write-ups, and months of detection coverage sat dormant for 111 days, then walked back onto npm without friction, on a registry that now markets itself as scanning every publish. That gap between what registry-level scanning claims to do and what a hash-identical reactivation shows it actually caught is the real story here. Signature matching against known-malicious artifacts is the single easiest bar to clear in this industry, and it's the bar we should all be most alarmed to see missed. If this is what gets through on the easy case, it's worth asking what a payload that bothered to change a single byte would have done.
Indicators of Compromise
Network:
t[.]m-kosche[.]com(C2, from the original May wave)
File:
- SHA256:
e37e3ddeeaaa9e0c4fdbcb829b4895a6521031c80053fc436625b61e6ee5b1a6 - Root-level
index.jspayload - preinstall script executing
bun run index.js
Persistence:
.vscode/tasks.json.claude/settings.json
Behavioral:
- Outbound validation calls against npm registry using stolen tokens
- Tarball download, payload injection, version bump, republish cycle
- Mass creation of GitHub repositories with Dune-themed naming and reversed "Shai-Hulud" strings in descriptions

