Due campagne malevole su npm sono emerse a tre settimane di distanza. A leggere i titoli si fondono in un unico messaggio: i pacchetti npm sono pericolosi. A leggere i report differiscono proprio nel punto che decide se uno sviluppatore abbia mai l’occasione di fermarli.
Caso uno: il worm che ha bisogno della tua fiducia
Un worm che ruba credenziali è comparso per primo in keyv@6.0.0 e il 4 agosto 2026 si è diffuso oltre gli spazi dei nomi Keyv e Cacheable, fino a centinaia di pacchetti.
La versione malevola ha aggiunto node setup.mjs come comando preinstall lasciando intatto il codice compilato della libreria. La prima fase verifica la presenza dell’ambiente Bun, lo scarica se serve e passa il controllo a un bundle compilato di 727.680 byte. Secondo l’analisi di SafeDep, quel bundle raccoglie materiale da GitHub, npm, cloud, Vault, Kubernetes, database e chiavi private, legge la memoria del runner di GitHub Actions e porta con sé la propria meccanica di pubblicazione su npm, che è il modo in cui continua a diffondersi.
Il repository conservava inoltre hook separati per Claude Code e Visual Studio Code. Contano, e conta altrettanto la riserva che il report vi allega: possono «eseguire il carico una volta che un utente dà fiducia allo spazio di lavoro o autorizza la configurazione del progetto».
C’è una porta. Qualcuno deve attraversarla.
Caso due: quello che non chiede
Il 21 agosto TrendAI ha segnalato quattordici pacchetti npm troianizzati che si spacciavano per utilità di calendario e di serie di giorni. Funzionano: la funzionalità promessa c’è, ed è quello che li tiene installati.
Sotto, il file di ingresso fa da caricatore per una backdoor Linux travestita da acceleratore matematico nativo. Il nome del file cambia da pacchetto a pacchetto (math-core.bin, calc-math.dat, calc-cache.bin e altri), ma il contenuto è sempre lo stesso beacon.
È sul meccanismo che questo caso si separa dal primo. Nelle parole dei ricercatori: «Quando il modulo viene caricato, individua il binario incluso, lo marca come eseguibile e lo lancia come processo di sfondo scollegato. Non serve alcuna chiamata a una funzione di hook di installazione; una sola importazione in qualsiasi punto del grafo delle dipendenze, anche transitiva, basta a eseguire il carico.»
Nessun hook di installazione. Nessuna richiesta di fiducia. Nessuna funzione esportata che qualcuno debba chiamare. Un’importazione tre livelli più in basso, in una dipendenza che non hai mai scelto, è sufficiente.
Perché la differenza è la notizia
Sono entrambi attacchi alla catena di fornitura di npm. Metterli in un unico avvertimento fa perdere l’unica parte che cambia quello che si fa.
Il caso uno è rallentato da una decisione umana. npm 12 blocca per impostazione predefinita gli script di ciclo di vita delle dipendenze non approvate, e gli hook dell’editor hanno bisogno che qualcuno dia fiducia allo spazio di lavoro. I client npm più vecchi e le altre vie di installazione che permettono quegli script restano esposti, quindi la protezione è reale e insieme condizionata.
Il caso due non ha quel passaggio. Il carico parte all’importazione, il che significa che le difese che contano sono quelle che non dipendono dal fatto che qualcuno si accorga di qualcosa: versioni di dipendenze fissate, disciplina sul lockfile, e sapere cosa c’è davvero nel proprio albero.
Chi se ne va di qui con «bisogna stare attenti ai pacchetti npm» ha saltato la metà che dice dove mettere lo sforzo.
I numeri sull’ampiezza non coincidono, e il report lo dice
È qui che la storia viene citata male, quindi ecco il quadro completo.
SafeDep ha verificato 353 versioni avvelenate su 79 nomi di pacchetto. Il suo monitoraggio collocava l’impronta più ampia a 442 versioni su 353 nomi. Aikido ha poi riportato almeno 868 pacchetti su 1.381 versioni.
Tre conteggi, tre fonti, e il report è esplicito: «nessuno dei due totali più ampi era riproducibile in modo indipendente a partire da un elenco pubblico completo alla data di chiusura».
Aggiunge una seconda avvertenza che pesa più della discrepanza: quei totali «contano artefatti di pacchetto malevoli, non sistemi vittima. Stabiliscono l’ampiezza della campagna, ma non mostrano quante macchine abbiano installato o eseguito il carico».
Quindi se ti capita un numero unico e sicuro su questa campagna, è stato scelto tra tre che si contraddicono, e in ogni caso conta pacchetti e non infezioni.
Il passo di bonifica che va contro l’istinto
È la frase più utile dei due report, e sfugge con facilità.
Il carico installa un sorvegliante della revoca delle credenziali. SafeDep consiglia a chi risponde all’incidente di rimuovere quel sorvegliante prima di ruotare token e chiavi esposti, perché è la revoca a farlo scattare: ruotare per primo può eseguire un gestore locale lasciato dall’attaccante.
La reazione istintiva a un furto di credenziali è ruotare tutto subito. Qui quell’istinto fa scattare la trappola.
La valutazione di Socket su chi è coinvolto è ampia: «ogni postazione di lavoro o runner che abbia eseguito una versione interessata va trattata come esposta sul piano delle credenziali».
Perché un elenco di pacchetti non ti salverà
Il report annota che il registro cambiava troppo in fretta per reggere un elenco fisso valido per l’intera campagna. Poche ore dopo i primi riscontri, versioni precedenti erano tornate a essere marcate come latest per almeno nove pacchetti dell’insieme iniziale di SafeDep.
La conseguenza pratica: le verifiche di esposizione devono usare nomi esatti di pacchetto, versioni risolte e lockfile, non un elenco salvato delle etichette correnti. Una lista di blocco a livello di spazio dei nomi rischia sia di lasciar fuori versioni avvelenate sia di segnalare versioni mai interessate.
La forma è nota. Un elenco che sembra autorevole, che è già vecchio quando lo si legge, e che dà risposte sicure in entrambe le direzioni.
Cosa portarsi via
Scopri se le tue vie di installazione eseguono script di ciclo di vita. Se sei su una versione di npm che li blocca per impostazione predefinita, il caso uno ha una porta davanti. Se non lo sei, non ce l’ha.
Renditi conto di quanto lontano arrivi un’importazione transitiva. Al caso due basta un modulo caricato in qualche punto del grafo, e questo rende la profondità delle dipendenze una proprietà di sicurezza e non una questione di ordine.
E se mai rispondi a un incidente di furto di credenziali, leggi l’ordine delle bonifiche prima di ruotare. Stavolta la prima mossa ovvia era proprio quella che fa scattare il carico.
Fonti
- The Hacker News, «Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks», 4 agosto 2026: https://thehackernews.com/2026/08/keyv-linked-npm-worm-poisons-hundreds.html (consultato il 26 agosto 2026). Origine dell’inizio in keyv@6.0.0, del meccanismo preinstall e della dimensione del carico, del materiale raccolto, dei tre numeri contrastanti sull’ampiezza e delle riserve che il report stesso vi appone, della riserva sugli hook dell’editor, dell’ordine di bonifica con il sorvegliante della revoca, della valutazione di Socket e della nota sulle etichette mutevoli del registro.
- The Hacker News, «14 Trojanized npm Packages Drop RedC2 4.0 Linux Backdoor With AI-Assisted C2», 21 agosto 2026: https://thehackernews.com/2026/08/14-trojanized-npm-packages-drop-redc2.html (consultato il 26 agosto 2026). Origine dei quattordici pacchetti, del meccanismo del caricatore, dei diversi nomi di file del binario e dell’identificazione del carico come beacon Linux RedShell.
- Entrambi i report esistono solo in inglese: le citazioni di questo articolo sono traduzione propria dall’originale, non citazioni letterali in italiano.
