Un worm informatico diffuso attraverso pacchetti npm ha compromesso 42 repository GitHub appartenenti a 11 proprietari legittimi, nascondendo codice malevolo all’interno di file JavaScript talmente grandi da sfuggire ai normali strumenti di ricerca della piattaforma. L’attacco, identificato con il nome testmetest, sfrutta una combinazione piuttosto insolita: payload offuscati da oltre 12 MB, credenziali sottratte agli sviluppatori e meccanismi di esecuzione automatica integrati negli assistenti AI per la programmazione.
La scoperta arriva dai ricercatori di JFrog Security Research, Guy Korolevski e Yair Benamou, che hanno pubblicato un’analisi approfondita dell’operazione.
L’evento si inserisce nella successione di attacchi alla supply chain software che hanno interessato npm e GitHub durante il 2026, a partire dalla campagna Mini Shai-Hulud, che ha coinvolto 314 pacchetti npm, fino alle varianti successive capaci di propagarsi autonomamente attraverso librerie e repository compromessi. Tra gli episodi più significativi figurano la compromissione della libreria Axios, l’attacco ai pacchetti npm associati a Red Hat e la campagna Megalodon, che ha coinvolto oltre 5.500 repository GitHub. Operazioni differenti, ma accomunate dallo sfruttamento delle credenziali degli sviluppatori, degli automatismi di pubblicazione e della fiducia accordata ai componenti software distribuiti attraverso canali ufficiali.
La vicenda presenta un aspetto particolarmente preoccupante: secondo la prima indagine di SafeDep, la nuova operazione testmetest sembrava limitata ad account controllati dagli aggressori. JFrog ha invece individuato repository autentici già compromessi, con attività riconducibili addirittura a luglio 2026. La campagna non era quindi soltanto un esperimento preparatorio.
Come il worm npm è riuscito a compromettere 42 repository GitHub
Il punto di ingresso è rappresentato da pacchetti pubblicati nel registro npm, alcuni dei quali presentavano nomi e descrizioni compatibili con normali librerie JavaScript.
SafeDep aveva inizialmente individuato 18 pacchetti associati alla campagna tra il 19 e il 25 ottobre; l’indagine successiva di JFrog ha ampliato l’inventario a 25 nomi di pacchetti e 82 versioni complessive, comprendendo anche release innocue e componenti utilizzati come copertura.
Una delle tecniche iniziali sfrutta binding.gyp, file di configurazione associato alla compilazione dei moduli nativi Node.js. Gli aggressori inseriscono un’espansione di comando che esegue index.js durante l’installazione, anche senza dichiarare un tradizionale script install nel file package.json.
Il caricatore applica una trasformazione dei caratteri, decifra uno stadio protetto con AES-128-GCM e individua oppure scarica Bun 1.2.18, utilizzato per eseguire il payload successivo. In alcune varianti il codice passa direttamente a bun run -; in altre finisce temporaneamente su disco prima dell’esecuzione.
Il trucco dei file enormi: malware invisibile alla ricerca GitHub
La caratteristica “inedita” dell’operazione riguarda le dimensioni dei file malevoli: come accennato nell’introduzione, i ricercatori hanno individuato nei repository compromessi file .github/init.js compresi tra circa 12,9 e 13,7 MB, progettati per contenere un caricatore offuscato e un secondo stadio nascosto.
La ricerca del codice di GitHub non indicizzava quei file, mentre le normali richieste alla Contents API non riuscivano a restituirne il contenuto. Durante la prima ricognizione, JFrog aveva trovato tracce dell’attacco in 26 repository, ma i file principali apparivano sostanzialmente vuoti attraverso i percorsi di consultazione utilizzati.
Solo passando alle Git Trees API e Git Blobs API, con l’enumerazione diretta degli oggetti Git, gli analisti hanno potuto accorgersi dei payload effettivi. L’estensione delle verifiche agli altri repository degli stessi proprietari ha portato il totale a 42.
Gli aggressori sfruttano piuttosto un punto cieco degli strumenti di analisi: un file può esistere regolarmente nel repository e partecipare all’esecuzione del progetto, pur rimanendo escluso dai risultati della ricerca.
JFrog ha identificato dieci varianti dei grandi file JavaScript. Le differenze derivano soprattutto dalla codifica dei caratteri e dalle chiavi di rotazione utilizzate per l’offuscamento. Dopo la decodifica, però, tutte riconducono allo stesso payload, con identico hash SHA-256: 10 differenti “involucri” nascondono un unico componente malevolo.
Claude, Gemini, Cursor e VS Code diventano possibili punti di attivazione
La seconda parte dell’attacco riguarda gli strumenti quotidiani degli sviluppatori. I repository compromessi contenevano configurazioni che sfruttavano gli hook di esecuzione automatica associati ad assistenti AI e ambienti di sviluppo.
Tra i percorsi individuati figurano .claude/settings.json, .gemini/settings.json, .cursor/mcp.json, .cursor/rules/setup.mdc e .vscode/tasks.json.
Nel caso di Claude Code, ad esempio, un hook SessionStart richiama node .github/init.js oppure tenta l’esecuzione con Bun. Altri file configurano meccanismi equivalenti per Gemini, Cursor e attività di Visual Studio Code.
Il rischio è evidente: un repository scaricato da GitHub può contenere istruzioni che tentano di eseguire codice quando lo sviluppatore avvia una sessione o apre un progetto, purché lo strumento utilizzato consenta effettivamente l’attivazione di quei meccanismi.
Come individuare i repository compromessi e proteggere gli sviluppatori
La prima indicazione è non affidarsi esclusivamente alla ricerca testuale di GitHub: per individuare i file utilizzati nella campagna occorre esaminare direttamente gli alberi Git, i blob e le modifiche apportate ai repository, anche quando gli strumenti abituali non restituiscono risultati.
Particolare attenzione meritano i file .github/init.js, le configurazioni degli assistenti AI, i workflow GitHub Actions inattesi e i branch temporanei chore/ci-* o deps/upd-*. Tra gli indicatori segnalati da JFrog figurano anche commit con la stringa skip-checks:true e file .napi_cache associati a moduli nativi sospetti.
Chi ha installato una delle versioni npm malevole dovrebbe considerare potenzialmente compromesso il sistema, ricostruire l’ambiente da fonti attendibili e sostituire le credenziali accessibili al processo infetto. La sola rimozione del pacchetto non garantisce che eventuali processi persistenti o token sottratti cessino di rappresentare un rischio.
Esiste anche una complicazione: alcune varianti della famiglia incorporano un wiper che può cancellare la directory personale dell’utente quando rileva la revoca del token GitHub rubato. Prima di procedere alla rotazione delle credenziali occorre quindi isolare il sistema e neutralizzare i componenti malevoli, seguendo una procedura di risposta agli incidenti.
Infine, è opportuno rivedere i permessi dei workflow e dei token di pubblicazione, verificare le dipendenze npm e applicare il principio del privilegio minimo. Le configurazioni eseguibili presenti in progetti sconosciuti meritano la stessa prudenza riservata agli script scaricati da Internet.