Een zelfvermenigvuldigende worm op npm heeft sinds dinsdagochtend honderden pakketten besmet, nadat aanvallers het GitHub-account kaapten van jaredwray, de beheerder van de cachebibliotheken keyv en cacheable, meldt beveiligingsbedrijf Aikido.
Het gaat niet om pakketten die je bewust hebt gekozen. file-entry-cache en flat-cache zitten volgens de meting van Wiz Research in 46,6 procent van alle gescande cloud- en code-omgevingen, keyv in 46,3 procent: ze komen mee als onderliggende afhankelijkheid van iets anders. Draaide je dinsdag een build op zo'n project, dan kan de payload al zijn uitgevoerd voordat de installatie klaar was. En omdat de malware npm-tokens, GitHub-tokens, AWS-sleutels, Kubernetes-secrets en Vault-tokens leest en daarmee zelfstandig nieuwe besmette versies publiceert, is de schade niet één pakket maar je hele sleutelbos.
De tellingen lopen uiteen, de richting niet
Aikido kwam op 4 augustus om 13.37 uur op minstens 868 besmette pakketten over 1.381 versies, samen goed voor ruim twee miljard installaties per maand. Wiz telde ruim 400 losse pakketten en dateert het begin op dezelfde dag, 9.00 uur UTC. SafeDep hield het op 1.684 vergiftigde versies over 420 pakketnamen, verdeeld over negen organisaties. BleepingComputer, dat de campagne ChainDrop doopte, komt op meer dan 1.300 pakketten met samen twee miljard downloads per maand.
Die spreiding zegt minder over onenigheid dan over tempo. Aikido zag in de piek elke paar minuten vijftig tot honderd nieuwe pakketten besmet raken, en iedere onderzoeker telt iets anders: pakketnamen, versies of hele scopes. Het bereik eronder is in elk geval geen randgeval. flat-cache haalt 565 miljoen downloads per maand, file-entry-cache 557 miljoen en keyv 127 miljoen per week.
Hoe de besmetting binnenkomt
Twee bestanden doen het werk. setup.mjs is de dropper, Math_Symbol.js de versluierde payload van 728 kB. Een preinstall-regel start de dropper zodra je installeert; die haalt de Bun-runtime van GitHub en voert de payload uit voordat npm klaar is. Je hoeft de code dus nooit te draaien. De installatie zelf is genoeg.
Wat er meegaat is breed: authTokens uit ~/.npmrc, GitHub-tokens (classic PAT, OAuth, App-tokens en JWT OIDC), AWS-sleutels met sessietokens plus EC2- en ECS-metadata, Kubernetes-serviceaccounttokens, Vault-tokens, Stripe-sleutels, Slack-tokens, SSH-sleutels, Terraform-state en Docker-registry-credentials. Op GitHub Actions-runners leest de malware het procesgeheugen van de secret store uit. Met de buitgemaakte npm-tokens publiceert hij daarna zelf nieuwe versies van pakketten van andere beheerders, en zo groeit de besmetting zonder dat de aanvaller nog iets hoeft te doen.
De gestolen gegevens verdwijnen naar GitHub-repositories die onder gekaapte identiteiten worden aangemaakt, met de omschrijving "Shai-Hulud: Here We Go Again". De commandoservers zitten niet in de code: de malware haalt die domeinen op uit een smartcontract op Ethereum, zodat de aanvaller ze kan wisselen zonder de payload aan te raken.

De AI-hoek zit in je editor, niet in npm
Het detail dat dit incident onderscheidt van een gewone pakketvergiftiging staat buiten de pakketbeheerder. In de gekaapte repository stonden een .claude/settings.json met een SessionStart-hook en een .vscode/tasks.json met een taak "Environment Setup", allebei wijzend naar de kwaadaardige setup-bestanden. Wie de map opent in Claude Code of VS Code, start de payload daarmee opnieuw, volledig buiten npm om.
De rem daarop is workspace trust. VS Code blokkeert automatische taken in een map die je niet vertrouwd hebt en Claude Code past dezelfde controle toe. Dat helpt alleen zolang je niet uit gewoonte op "trust" klikt bij elke repository die je binnenhaalt. En het gevaar was er niet mee weg: npm zette de oude releases op 4 augustus in de middag terug als latest, maar de vergiftigde hookbestanden bleven op de main-branch van de repository staan, constateert The Hacker News.
Wat je vanavond controleert, in deze volgorde
De volgorde is hier geen detail, want er zit een dodemansknop in de malware. OX Security beschrijft dat het pakket sporen wist zodra het gestolen GitHub-token wordt ingetrokken. SafeDep adviseert daarom eerst de watcher die op die intrekking let te verwijderen, en pas daarna te roteren. Vijf stappen:
- Vergelijk je lockfile met de lijsten. Wiz, Aikido, Socket en OX publiceerden lijsten met besmette pakketten en versies. Zoek in
package-lock.jsonen in je buildlogs naar keyv, cacheable, cacheable-request, cache-manager, flat-cache en file-entry-cache. - Zoek de sporen op je machines. Een bestand
node_modules/keyv/Math_Symbol.js, een map/tmp/bun-dl-*, uitgaand verkeer naar npm-cache[.]com, pypi-get[.]com of js-mirror[.]com, en de user-agentBun/1.3.13in je logs. - Behandel een geraakte omgeving als gecompromitteerd. Niet alleen de laptop van de ontwikkelaar, ook de CI-runner en de deployomgeving. Opnieuw opbouwen is veiliger dan opschonen.
- Roteer alles wat de payload leest. npm- en GitHub-tokens eerst, daarna cloudsleutels, Kubernetes- en Vault-secrets, Stripe- en Slack-tokens en SSH-sleutels.
- Zet installatiescripts uit waar dat kan. Installeren met
npm ci --ignore-scriptsin je pijplijn blokkeert precies depreinstall-stap waarlangs dit binnenkomt.
Waarom dit sneller ging dan de vorige keer
De aanval past in een reeks die sinds midden juni loopt. In juni kregen ruim 140 Mastra-pakketten voor AI-agenten een verborgen wachtwoordsteler via de gekaapte npm-scope, medio juli werden vier AsyncAPI-pakketten besmet, waaronder @asyncapi/specs met ruim twee miljoen downloads per week. Steeds hetzelfde patroon: geen obscuur typosquat-pakket, maar de publicatieketen van een vertrouwd project.
Wat verschuift is de snelheid. Deze golf groeide volgens Aikido van tien pakketten naar meer dan achthonderd in een halve werkdag. Geen handmatig controleproces houdt dat bij, dus de verdediging moet in je beleid zitten en niet in je reactietijd. Begin juli adviseerde de FBI om een pakketversie pas te installeren nadat die zeven dagen bestaat, juist omdat kwaadaardige versies meestal binnen enkele dagen worden ontdekt en teruggetrokken. Combineer dat met een vastgelegde lockfile en installeren via npm ci, dat stopt zodra lockfile en package.json niet overeenkomen, en een golf als die van vandaag komt op de dag dat hij losbarst simpelweg je omgeving niet in.
Veelgestelde vragen
Grip op je eigen stack
Een incident als dit legt bloot hoeveel code van vreemden er in je bedrijf draait zonder dat iemand er eigenaar van is. Ik denk mee over je architectuur, bouw en koppel je systemen en richt je pijplijn zo in dat updates en secrets geregeld zijn, self-hosted waar dat kan.
Dit artikel is geproduceerd samen met het Agent Team. Meer over de redactie.
