First Archive
#npm #supplychain #ShaiHulud #OnyxAudit
The badge
At 20:38 UTC tonight I saved a page to the Internet Archive from a phone in Pinetown. The Wayback Machine returned a small grey badge next to the confirmation: First Archive.
The page was Aikido Security's write-up of the npm supply chain attack that had been running for eleven hours by then, an attack every major security outlet in the world had covered that afternoon, and which six of them had quoted a specific number from. Nobody had preserved it. Not one person, in eleven hours, had thought to fix the source in place before it moved.
It had already moved.
What happened, briefly
Shortly after 09:00 UTC on 4 August 2026, someone took control of the GitHub account belonging to the maintainer of keyv, a small key-value storage library, along with the wider family of caching utilities the same person maintains: cacheable, flat-cache, file-entry-cache, cacheable-request, cache-manager.
Rather than steal a publishing token and push from a laptop, the attacker committed malicious files straight to the main branch and triggered the project's ordinary release workflow. Snyk logged the commit preparing keyv 6.0.0 at 09:02, and a second commit at 09:04 adding execution hooks for VS Code and Claude Code. The first poisoned release landed on the registry around 09:35. By 09:38 a package belonging to a completely unrelated account had been infected, because the payload steals publishing credentials and uses them to republish itself into whatever else those credentials can reach.
It is a worm. That detail matters more than it looks, and I will come back to it.
What I want to write about is not the attack. Twenty vendors have covered the attack, several of them well. What I want to write about is what happened to the numbers in the eleven hours afterwards, because I spent this morning publishing a piece arguing that INTERPOL had read a vendor telemetry share as an incidence figure, and by lunchtime I was watching the same class of error happen live in my own field, in real time, about an event that was still unfolding while it was being counted.
Four things were reported today as facts. All four are doing less work than they appear to.
One: the count

Aikido posted a running total, timestamped 13:37 CEST. Six outlets picked it up.
BleepingComputer reported at least 868 packages across 1,381 versions. Strobes cited Aikido at 868 across 1,381. DevOps.com attributed 868 across 1,381 to Aikido's named researcher. Developer-tech carried 868 across 1,381 at 13:37 CEST. CyberSecurityNews and Cryptika carried 868 across 1,381, but dated the update 13:20.
Aikido's page tonight reads 434 packages across 1,381 versions, same timestamp, same sentence structure, half the packages.

The version count never moved. Only the package count did, and it moved by exactly a factor of two.
The independent enumerations sit with the lower figure, not the higher one. Wiz counted over 400 distinct packages in an update at 15:25 UTC. SafeDep enumerated 420 package names against the registry, across 1,684 poisoned versions. Aikido's own prose, in the body of the same article, says they observed over 400 packages infected through community spread.

So the 868 is the outlier, and the 868 is the number the world is carrying.
I cannot tell you what happened. There is no earlier snapshot of that page anywhere, because I was the first person to archive it, at 20:38, six hours after the figure entered circulation. Whatever the page said at 13:37 is now unrecoverable. That possibility closed while nobody was looking.
Nor is anyone at fault here in any way I can demonstrate. Aikido's own researcher told DevOps.com that they were seeing fifty to a hundred newly infected packages every few minutes, that the count had passed 1,280, and that the attack was moving faster than they could update the blog. A vendor revising figures during a live incident is doing exactly what you want a vendor to do.

The finding is narrower than blame, and more useful. A number was published, travelled to at least six outlets including a heavyweight, and then changed at source with no correction notice attached. The outlets still carry the original. The number has come loose from the thing that produced it, and it is now the headline scale of the incident.
Current figures in circulation for one event, within nine hours: 434, 868, over 400, 420 names across 1,684 versions, and over 1,280.
Two: the reach
Every write-up leads with keyv and its 127 million weekly downloads. It is a genuinely enormous number and it is not an exposure figure.
Strobes did the work almost nobody else did: they installed the affected dependency chains and checked which of the malicious versions the declared version ranges would actually accept. Software dependencies are usually declared as a range rather than a fixed version, so what matters is not how popular a package is but whether the poisoned release falls inside the range everybody's projects already declared.
keyv 6.0.0 does not. Nothing in the tree asks for version 6, so every range pointing at version 4 or version 5 refuses it. The only people who received malicious keyv are those who explicitly asked for the newest release or had pinned themselves to 6.
The releases that installed silently were cacheable-request 13.0.20, cache-manager 7.2.10 and @cacheable/utils 2.5.1, all small patch increments sitting comfortably inside ranges that were already live in thousands of projects.
The package everyone named was the one that was blocked. The three that actually spread went largely unnamed for most of the day.
There is a bleak detail underneath this. keyv's own documentation states that version 5 is in maintenance mode with no new major releases planned, so a surprise 6.0.0 is an anomaly a human reviewer notices immediately. The anomaly that made it obvious is the same anomaly that made it harmless.
And the depth is the point of the target selection. A typical chain runs from ESLint, the linting tool almost every JavaScript project uses, down through file-entry-cache, then flat-cache, then keyv. Nobody chose any of it. Advice to audit your dependencies assumes you know what your dependencies are, and four levels down, you do not.
Three: the provenance
After the earlier waves of this campaign, the ecosystem's answer was npm provenance: a cryptographic attestation binding a published package to the exact repository, commit and workflow run that built it, signed through Sigstore.
Every poisoned package published today carries valid provenance, signed by GitHub Actions. Every cryptographic check passes.
It passes because the attestation is honest. The tarballs really were built by that repository, from that commit, in that workflow. The attacker did not forge anything or go around the release path; they went through it, having taken the account that owns it. When the attacker controls the repository, the malicious commit is the source of truth, and a signature over the source of truth is accurate.
Provenance answers where a build came from. It has never claimed to answer whether the code is safe, and it was never designed to. The problem is that a green badge reads as a safety signal to almost everyone who sees one, and any scanning gate configured to treat valid provenance as a pass condition passed this attack without hesitation.
By Strobes' own comparison, this is the second npm compromise in three months to ship malware with legitimate attestations.
Four: the actor
Microsoft Threat Intelligence reported observing the same pattern across all affected packages, and inferred from that consistency a single actor operating with multiple stolen tokens.

The observation is sound. The inference does not carry on its own, for two reasons.
The malware is self-propagating. It reads the stolen publishing token, lists every package that token can publish to, unpacks each one, increments the version, injects itself and republishes. Pattern consistency across hundreds of packages is what that machinery produces automatically, from one initial compromise, with nobody at a keyboard. Identical patterns are the expected output of a worm, not evidence of a single hand.

And the toolkit is public. The Mini Shai-Hulud family was open-sourced on GitHub in May, and Palo Alto's Unit 42 has already noted that the resulting copycat activity makes attribution to the original crew harder, not easier. Wiz assessed today's payload as a descendant of that family and stated plainly that there is no confirmed attribution.
BleepingComputer reports the worm has been named ChainDrop. Most coverage still calls it Mini Shai-Hulud. The naming is diverging too.
None of this means Microsoft is wrong. It means the reasoning offered in public does not get you there yet, and the difference between those two statements is the whole job.
What I could check myself
I work from a phone. I have no laptop, no Node installation and no way to run the dependency commands Strobes ran, so I will not pretend otherwise; that finding is theirs and I have credited it as theirs.
Two things I could do.
I added the four published network indicators to my NextDNS denylist and searched my logs: npm-cache.com, the exfiltration host, plus three public Ethereum RPC endpoints the payload uses as a fallback command channel. No hits. Recorded with the limitation attached, because my NextDNS sits at browser level rather than system level, so a clean result proves my browser did not resolve those hosts, not that my device did not. Anyone can run this check in about two minutes, and the three Ethereum endpoints are legitimate public infrastructure, so blocking them will break genuine web3 sites; only the first has no honest use.

I also pulled my own deployment record. My research site builds from a GitHub repository, which sounded like exposure until I looked: five second deploy, one asset changed, one header rule, no framework, no plugins, no functions, and nothing published since 29 June. It is a static file upload. No install step runs, so no install-time code executes.
That is a negative finding, and it is the honest half of the piece. My exposure was never the phone in my hand. If I had ever had exposure it would have been in a build runner somewhere, executing third-party code on my behalf, and I do not have one. Simplicity turned out to be the control.
Tiering
Tier A. Aikido's page reads 434 packages across 1,381 versions at 13:37 CEST. Six outlets carry 868 across 1,381 attributed to Aikido. Wiz reports over 400. SafeDep enumerated 420 names. Aikido's researcher gave DevOps.com over 1,280. Every poisoned release carries valid GitHub Actions provenance. keyv 6.0.0 is refused by the declared ranges in the tree. All archived, all timestamped below.
Tier B. That Aikido published 868 and later revised it downward. Six outlets converging on a near-identical sentence is strong, but no snapshot exists and none ever will, so this stays an inference permanently.
Tier C, not published. Why the figure changed, when it changed, or whether anyone intended anything by it. I do not know, and neither does anyone else writing about it.
What this is not
This is not an accusation against Aikido, whose researchers were the first to publish, published in detail, published the indicators, and were straightforwardly outrun by the thing they were counting. It is not an accusation against the outlets, who quoted their source accurately at the moment they quoted it. It is not a claim that anybody was careless.
It is an account of a mechanism. Under time pressure, during a live incident, the only numbers available are provisional ones, and provisional numbers harden into settled facts the moment they are quoted by somebody large. The correction, if there is one, does not travel. The original does.
This morning I published a piece about INTERPOL's African Cyberthreat Assessment reading a single vendor's telemetry share as though it measured incidence across a continent. I did not expect to watch the same failure occur eleven hours later, in my own discipline, about an event still in progress, or to find that the only fixed record of it was one I made myself on a phone at ten to nine at night.
The badge said First Archive. That is not a compliment to me. It is a measurement of how many people were watching the source.
Sources
All captured 4 August 2026, times UTC.
- Aikido Security, keyv and friends compromised:
web.archive.org/web/20260804203828/(20:38:28, first archive) - BleepingComputer, ChainDrop npm supply chain attack:
web.archive.org/web/20260804201821/(20:18:21) - DevOps.com, fast-moving Shai-Hulud attack:
web.archive.org/web/20260804202605/(20:26:05) - CyberPress, worm compromises 868 packages:
web.archive.org/web/20260804203442/(20:34:42) - Strobes Security, keyv and cacheable explained:
web.archive.org/web/20260804204323/(20:43:23) - Developer-tech, Aikido tracks infection surge:
web.archive.org/web/20260804204529/(20:45:29) - Wiz, keyv and cacheable hijacked:
web.archive.org/web/20260804204751/(20:47:51) - CyberSecurityNews, keyv compromised:
web.archive.org/web/20260804205017/(20:50:17)
Additional: Snyk Security Research commit timeline; Microsoft Threat Intelligence advisory, 4 August 2026; Palo Alto Unit 42 npm threat landscape, updated 15 July 2026.
Clayton Bax
Published under ONYX Digital Intelligence Following the #OnyxAudit methodology.
- X: @onyxaudit
- Email: onyxdigitalintelligence85@protonmail.com
- https://github.com/Baximus855
- @Onyx_Digital@mastodon.social
"Adjacent to true is not true."
Truth has no flag nor favour, only a standard. And it's heavy