ChainDrop: il worm npm che ruba le credenziali del tuo assistente AI
Il 4 agosto 2026 ChainDrop ha avvelenato oltre 400 pacchetti npm con 2 miliardi di download mensili in meno di quattro ore — ed è il primo worm a rubare i token degli assistenti AI e a nascondersi negli hook di Claude Code.
Il 4 agosto 2026, tra le 09:35 e circa le 13:20 UTC, un worm npm auto-propagante ora tracciato come ChainDrop ha avvelenato oltre 400 pacchetti appartenenti a decine di manutentori non collegati tra loro. StepSecurity ha contato 444 pacchetti e 2.212 versioni malevole in meno di quattro ore; il parco installato dei pacchetti colpiti è nell'ordine dei due miliardi di download al mese. Il paziente zero è stato [email protected] — una libreria di caching con 153,7 milioni di download settimanali — pubblicato alle 09:35:00Z esatte attraverso un workflow legittimo di trusted publishing autenticato via OIDC.
Due elementi rendono ChainDrop degno di un'analisi e non dell'ennesimo avviso "ruota il token npm". Primo: le versioni malevole portavano provenance SLSA e attestazioni Sigstore valide — erano crittograficamente indistinguibili dalle build autorizzate. Secondo: ChainDrop è il primo worm che tratta l'assistente di coding AI sia come deposito di credenziali sia come vettore di reinfezione. Legge i file di autenticazione di .claude, .cursor, .openai e .anthropic, e impianta persistenza dentro gli hook di Claude Code e nel tasks.json di VS Code. Se il tuo modello mentale di difesa supply-chain si ferma a "controlla la firma", questo incidente è il controesempio.
Come si propaga davvero il worm npm ChainDrop
La meccanica è un affinamento della stirpe Shai-Hulud — la stessa famiglia dietro IronWorm a giugno e i pacchetti con provenance SLSA a maggio. Il ciclo è brutalmente semplice:
- Un pacchetto include un hook di ciclo di vita
"preinstall": "node setup.mjs".setup.mjsscarica il runtime legittimo Bun v1.3.13 dalle release GitHub reali dioven-sh/bun, lo posiziona in$TMPDIR/bun-dl-*ed esegue il secondo stadio — un payload Bun-bundled da 727.680 byte (Math_Symbol.js/math_init.js). - Il payload raccoglie ogni credenziale raggiungibile, poi verifica per ogni token npm rubato il permesso di scrittura sui pacchetti e la capacità di bypass 2FA.
- Per ogni pacchetto pubblicabile con quel token, scarica l'ultimo tarball, inietta il loader, incrementa la patch version e ripubblica.
Poiché il percorso di ripubblicazione sfrutta il trusted publishing di GitHub Actions, le nuove versioni malevole ereditano provenance valida. Secondo l'analisi di Semgrep, il worm saltava da un'organizzazione all'altra ogni due-sette minuti, colpendo scope come @servicetitan, @qlik, @nebula.js e @ornikar. The Hacker News ha riportato 546 repository GitHub pubblici creati quel giorno con la descrizione "Shai-Hulud: Here We Go Again" — i dead-drop di esfiltrazione del worm.
"La provenance dimostra l'origine della build, non l'autorizzazione." — analisi ChainDrop di Microsoft Security, 4 agosto 2026
Quella frase è tutta la storia. L'attaccante non ha falsificato una firma. Ha compromesso l'account GitHub di un manutentore, spinto un commit avvelenato e lasciato che il workflow di release del progetto firmasse il malware al posto suo. Ogni attestazione era autentica.
La parte nuova: credenziali AI e hook di Claude Code
Le ondate Shai-Hulud precedenti prendevano il solito insieme — chiavi SSH, ~/.aws, token npm, Vault, Kubernetes, segreti del runner GitHub Actions estratti direttamente da /proc/<pid>/mem. ChainDrop aggiunge una categoria che nessuno stava sorvegliando:
- File di credenziali degli strumenti AI. Il payload legge
.claude/credentials.json,.cursor/credentials.json,.openai/auth.jsone.anthropic/auth.json— le chiavi API che i tuoi sviluppatori hanno incollato nei loro assistenti di coding, spesso chiavi a carico dell'organizzazione con rate limit generosi e, sempre più, scope di esecuzione di strumenti. - Persistenza nell'assistente AI. Usando credenziali GitHub rubate, il worm committa due file nei repository che riesce a raggiungere:
.claude/settings.jsoncon un hookSessionStartche rilancia il dropper la volta successiva che uno sviluppatore apre Claude Code in quel repo..vscode/tasks.jsoncon un task impostato surunOn: folderOpen, che eseguesetup.mjsnel momento in cui la cartella viene aperta in VS Code.
Entrambi i commit erano camuffati come firmati da claude <[email protected]> o da github-actions[bot] con firma verificata. L'effetto è un percorso di infezione da sviluppatore a sviluppatore che non richiede a nessuno di eseguire npm install. Un collega clona il repo, lo apre nell'editor, e il prompt di workspace-trust che ormai ha imparato a cliccare senza guardare fa ridetonare il payload. È persistenza all'avvio in stile T1547.010 innestata sugli strumenti di cui gli sviluppatori oggi si fidano di più.
La lezione è scomoda: man mano che gli assistenti di coding AI diventano attori privilegiati nel ciclo di sviluppo — leggono il codice, custodiscono chiavi API, eseguono comandi shell tramite hook — i loro file di configurazione diventano il nuovo ~/.bashrc. ChainDrop è la prova che gli attaccanti lo sanno già.
Il C2 che non ha bisogno di un dominio
Il command-and-control di ChainDrop merita attenzione perché sconfigge del tutto le difese basate su blocklist di domini. Invece di un server hardcoded, il payload chiama uno smart contract Ethereum — 0xE1f2395ee43e45A1556EC6438a88c31B83493103, function selector 0x53ed5143 — interrogando in sequenza fino a 75 endpoint RPC pubblici. Il contratto restituisce una lista di domini cifrata in AES-256-GCM; al momento dell'analisi risolveva a npm-cache[.]com:443/router. È la stessa tecnica EtherHiding che abbiamo sezionato con ACR Stealer: il dead-drop resistente ai takedown è una lettura sulla blockchain, e ruotare il C2 costa all'operatore una singola transazione economica.
L'esfiltrazione è gzip → JSON → AES-256-GCM → RSA-OAEP-SHA256, inviata in POST a /router. Esiste un fallback su commit GitHub firmato con il marker thebeautifulmarchoftime. Niente di tutto questo tocca un nome di file o un hash per cui il tuo EDR abbia una firma. Ciò che tocca, invece, è la rete.
Remediation
Tratta qualsiasi workstation o runner CI che abbia installato una versione colpita come credential-exposed, non semplicemente come "da aggiornare". Un runbook completo:
1. Sono impattato?
Controlla installazioni e lockfile nella finestra di esposizione (4 agosto 2026, ~09:35–13:20 UTC):
# qualsiasi dipendenza che risolve a una patch compromessa, anche transitiva
npm ls keyv flat-cache file-entry-cache cacheable-request cache-manager 2>/dev/null
# scansiona node_modules per gli artefatti del worm
find . -path '*/node_modules/*' \( -name 'setup.mjs' -o -name 'Math_*.js' -o -name 'math_init.js' \) 2>/dev/null
# persistenza a livello repo che il worm impianta
git log --all --diff-filter=A -- '.claude/settings.json' '.vscode/tasks.json'
Controlla anche le cache CI e le immagini golden runner — un tarball avvelenato scritto in una cache condivisa reinfetta ogni build successiva.
2. Patch — non c'è una CVE, c'è una soglia di versione
Non è una vulnerabilità con una release corretta; sono versioni compromesse di pacchetti legittimi. Fissa l'ultima versione nota-buona pubblicata prima delle 09:35Z del 4 agosto (ad esempio [email protected], [email protected], [email protected]) tramite npm overrides, poi reinstalla pulito:
npm install --ignore-scripts
Aggiorna a npm CLI v12+ e abilita min-release-age — la v12 blocca di default gli script di ciclo di vita non approvati e avrebbe neutralizzato del tutto il trigger preinstall. Le versioni npm precedenti restano esposte.
3. Non puoi ricostruire tutto ora? — controlli compensativi
- Imposta
ignore-scripts=truein.npmrca livello di organizzazione fino al triage. - Applica un cooldown sulle dipendenze (
min-release-age) affinché un pacchetto vecchio di pochi minuti non possa entrare in una build. - Richiedi review/approvazione sui workflow di trusted publishing di GitHub Actions e ambienti protetti — è il canale di propagazione.
4. Caccia alla compromissione (MITRE ATT&CK)
| Segnale | Tecnica |
|---|---|
node setup.mjs da un preinstall, seguito da un download Bun da oven-sh/bun durante l'install |
T1195.002 Supply-Chain Compromise · T1059.007 |
Letture di .aws, .ssh, file auth di .claude/.cursor/.openai; scraping di /proc/<pid>/mem per segreti del runner |
T1552.001 Credentials in Files · T1528 Steal Access Token |
Nuovo hook SessionStart in .claude/settings.json o runOn: folderOpen in .vscode/tasks.json su un repo |
T1547.010 Startup Persistence |
Traffico in uscita verso endpoint RPC Ethereum (decine, in sequenza), poi verso npm-cache[.]com:443/router |
T1041 / T1567 Exfil su C2 / servizio web |
gh-token-monitor.sh con nuovo servizio systemd o LaunchAgent macOS che interroga api.github.com/user ogni 60s |
T1098 Account Manipulation |
Estendi la finestra di look-back per l'esfiltrazione di credenziali alla tua storia infostealer, non solo a questa settimana — il comportamento precede ChainDrop.
5. Eradica e verifica — l'ordine conta
Il worm installa un token-monitor con un handler distruttivo che scatta quando il token GitHub sorvegliato viene revocato. Quindi:
- Rimuovi prima il token-monitor (
~/.local/bin/gh-token-monitor.she il relativo servizio/LaunchAgent), prima di toccare qualsiasi credenziale. - Poi ruota — ogni token npm, PAT GitHub e segreto legato a OIDC, chiave cloud, service account Kubernetes e credenziale Vault presenti sull'host durante l'install. Ruota da una macchina pulita.
- Revoca le chiavi API degli assistenti AI che risiedevano in
.claude/.cursor/.openai/.anthropic— considerale bruciate. - Svuota le cache npm/yarn e ricostruisci i progetti e le immagini di base impattate da una baseline nota-buona.
- Verifica per assenza: conferma che gli hash compromessi siano spariti da ogni cache e artifact store, e che nessun commit di persistenza
.claude/.vscodesopravviva su alcun branch.
Dove si colloca Zero Hunt
Ogni controllo statico che ChainDrop avrebbe dovuto far scattare — firma valida, provenance attestata, nome del pacchetto invariato — è passato. L'unica cosa che il worm non poteva falsificare è il suo comportamento sulla rete: un processo node durante npm install che contatta decine di endpoint RPC Ethereum, poi un dominio con cui la tua rete non ha mai parlato, per inviare in POST un blob avvolto in RSA. È un'anomalia di traffico molto prima di essere un IOC noto.
Il pilastro AI Traffic Analysis di Zero Hunt è costruito esattamente per questa finestra. Un modello di deep learning proprietario — quattro teste di inferenza parallele (traffico sospetto, classificazione malware, identificazione del tipo di attacco, fingerprinting applicativo), addestrato su miliardi di sequenze PCAP e in esecuzione localmente sulla GPU dell'appliance a 2,7+ Gbit/s — segnala il fan-out sequenziale delle RPC e l'egress verso un ASN mai visto mentre l'install è in corso, non nel digest SIEM del mattino dopo. Vede un C2 che non ha dominio ed esfiltrazione che non ha firma, perché valuta la forma della sessione, non una blocklist.
Il lato offensivo chiude il cerchio. Lo swarm generativo a 10 agenti di Zero Hunt può essere puntato sul tuo percorso di release per rispondere alla domanda che ChainDrop ha posto a tutti gli altri: il nostro workflow di trusted publishing è abusabile, e un token di manutentore rubato si propagherebbe? Ogni exploit è generato per ambiente da un LLM locale, ricontrollato in backtest nell'AI Gym prima di essere eseguito e firmato ECDSA per ogni finding — così la risposta è evidenza, non stima. La provenance ti diceva dove un pacchetto è stato costruito. Nessuno dei due ti dice che era autorizzato; il traffico e il test sì.