Attore non attribuitocritical
Axios, il manifest e il token che nessuno aveva revocato
Il 31 marzo 2026 due release malevole di axios aggiungono una dipendenza-trappola senza toccare una riga del codice sorgente. npm aveva introdotto il Trusted Publishing OIDC proprio per impedirlo: l'attore l'ha aggirato con un token classico già emesso.
Chi ha fatto la code review di axios il 31 marzo 2026 non avrebbe trovato nulla. Non perché fosse distratto: perché il codice sorgente della libreria non era stato toccato. Nemmeno una riga. L'unica modifica stava nel package.json — una dipendenza in più, un nome plausibile, plain-crypto-js. Quella riga sola bastava a piazzare un RAT su ogni macchina che eseguisse npm install.
axios è il client HTTP di fatto standard dell'ecosistema JavaScript: oltre 70 milioni di download a settimana, secondo la stima riportata da Microsoft. Non è una libreria: è infrastruttura. E la compromissione non ha una CVE, perché non c'è nulla da correggere nel prodotto. È la distribuzione ad essere stata compromessa, non il software. L'identificatore da citare è GHSA-fw8c-xr5c-95f9.
plain-crypto-js nel package.jsonL'origine
Il 31 marzo 2026 vengono pubblicate su npm axios@1.14.1 e axios@0.30.4. Sono entrambe malevole. Le ultime versioni sicure restano 1.14.0 e 0.30.3. Il 1° aprile alle 21:00 UTC Microsoft Threat Intelligence pubblica l'analisi tecnica; il 20 aprile CISA emette il proprio alert.
L'attore ha ottenuto accesso pubblicativo all'account npm del maintainer. Come, Microsoft non lo dice: il vettore iniziale non è specificato nel report, e va trattato come sconosciuto, non come "phishing" per default. Circola anche una finestra di esposizione di "meno di tre ore": proviene da fonti secondarie e non è confermata sulla fonte primaria. Trattatela come indicativa. Tre ore su un pacchetto da 70 milioni di download settimanali restano comunque un numero enorme di build in CI.
Ed è qui che sta il dettaglio che conta. npm aveva introdotto il Trusted Publishing via OIDC esattamente per rendere impossibile questo scenario: niente più token statici da rubare, ma credenziali effimere legate alla pipeline di build. L'attore non l'ha sconfitto. L'ha aggirato, usando un token classico già emesso in precedenza e mai revocato. La mitigazione "by design" era in campo e ha funzionato per ciò che copriva. Semplicemente non copriva il passato: una nuova architettura di sicurezza non protegge retroattivamente le credenziali emesse sotto la vecchia. Finché il token vecchio vive, il nuovo modello è decorativo.
La catena d'attacco
La preparazione è la parte più interessante, ed è quella che quasi nessuno racconta.
- 01Seeding
plain-crypto-js4.2.0 viene pubblicato pulito, senza payload - 02Il payloadla 4.2.1 aggiunge uno script di install mai importato dal runtime
- 03Il manifestle due release di axios aggiungono solo la dipendenza al
package.json - 04
npm installlo script post-install contatta il C2sfrclak[.]com:8000 - 05Payload per OSRAT persistente su macOS, Windows o Linux, poi autopulizia
Prima il seeding. L'attore pubblica plain-crypto-js in versione 4.2.0: pulita, innocua, priva di payload. Serve solo a esistere. A costruire storia, download, un profilo npm che non sembri nato ieri. È la stessa logica di un conto bancario aperto mesi prima di una truffa. Solo dopo arriva la 4.2.1, identica in facciata, con in più uno script di installazione (node setup.js) che non viene mai importato dal codice runtime. Non serve che qualcuno lo chiami: npm install lo esegue da solo.
Poi il colpo chirurgico. Le due release di axios si limitano ad aggiungere plain-crypto-js alle dipendenze. Nessuna modifica al sorgente (T1195.001). Ogni controllo che guardi il codice della libreria passa. Il diff pericoloso sta nel manifest, dove pochi guardano con la stessa attenzione.
All'installazione lo script post-install si decodifica a runtime e contatta il C2 sfrclak[.]com:8000 su HTTP (T1071.001). Il server risponde con un payload specifico per sistema operativo, selezionato in base al body della richiesta POST: product0 per macOS, product1 per Windows, product2 per Linux (T1105). Il risultato è un RAT persistente, diverso per piattaforma: AppleScript che deposita un binario su macOS; VBScript che innesca PowerShell su Windows (T1059.001), con persistenza via chiave di registro HKCU\...\Run\MicrosoftUpdate (T1547.001); Python su Linux (T1059.006).
Poi la pulizia. Lo script rimuove setup.js e sostituisce package.json con una versione pulita — così l'artefatto che vi ha infettati sparisce dal disco. I nomi scelti per gli impianti completano il quadro: wt.exe, com.apple.act.mond (T1036.005), roba che in una lista di processi non fa alzare un sopracciglio.
Detection
Cercate il C2, non il pacchetto: il pacchetto si è cancellato da solo.
- Dominio:
sfrclak[.]com— IP:142.11.206.73:8000 - Percorso C2 statico:
hxxp://sfrclak[.]com:8000/6202033 - Artefatti Windows:
%PROGRAMDATA%\wt.exe,%PROGRAMDATA%\system.bat - Artefatti macOS:
/Library/Caches/com.apple.act.mond - Artefatti Linux:
/tmp/ld.py - Microsoft Defender:
Trojan:JS/AxioRAT.DA!MTB,Backdoor:MacOS/TalonStrike.A!dha,Trojan:Python/TalonStrike.C!dha
Il segnale più affidabile resta il traffico in uscita dai runner di build: un container CI che parla HTTP con un host mai visto sulla porta 8000, durante npm install, è già la risposta.
Rimedi
# 1. Tornare alle versioni sicure
npm install axios@1.14.0 # oppure axios@0.30.3
# 2. Pinnare la versione esatta: via ^ e ~
# "axios": "1.14.0" <-- non "^1.14.0"
# 3. Svuotare la cache: le versioni malevole possono essere ancora lì
npm cache clean --force
# 4. Disattivare gli script di install per default
npm config set ignore-scripts true
Poi la parte che nessuno ama: audit dei log CI/CD nella finestra del 31 marzo, e rotazione di TUTTI i secret esposti a quelle build. Non i secret "importanti": tutti. Un RAT sul runner ha avuto accesso all'ambiente per intero.
Sul lungo periodo: Trusted Publishing via OIDC — e, subito dopo, la revoca sistematica dei token classici residui, altrimenti si ripete l'aprile 2026.
Cosa insegna
La lezione non è "controllate le dipendenze". È più scomoda: la vostra superficie d'attacco include le credenziali che avete smesso di usare ma non avete revocato. L'ecosistema aveva costruito la difesa giusta, l'aveva distribuita, l'aveva documentata — e l'attacco è passato dalla porta lasciata aperta dall'architettura precedente.
E poi: npm install non è un download. È esecuzione di codice arbitrario di terzi con i vostri privilegi. Lo sappiamo tutti, e continuiamo a lanciarlo su runner che tengono in memoria le chiavi di produzione.