Le 31 mars 2026 l'une des bibliothèques les plus utilisées de tout l'écosystème JavaScript a été transformée en arme. Pendant environ trois heures, quiconque a installé ou mis à jour Axios — le client HTTP aux 100 millions de téléchargements hebdomadaires — a reçu un cheval de Troie d'accès à distance (RAT) capable de prendre le contrôle complet de sa machine. L'attaque s'est auto-détruite pour effacer ses traces.
Voici exactement ce qui s'est passé, comment ça fonctionne, et surtout comment vous en protéger.
Le contexte : pourquoi Axios est une cible de choix
Axios est le client HTTP le plus populaire de l'écosystème JavaScript. Il est utilisé dans pratiquement tout projet Node.js ou application frontend qui effectue des requêtes réseau. Les chiffres parlent d'eux-mêmes : entre 83 et 300 millions de téléchargements hebdomadaires selon les sources, plus de 2 millions de paquets dépendants, et une présence massive dans les frameworks frontend, les services backend et les applications d'entreprise.
Compromettre Axios, c'est potentiellement atteindre des millions de développeurs et d'environnements de production en une seule opération. Et c'est exactement ce qu'un attaquant a fait ce 31 mars 2026.
Chronologie précise de l'attaque
L'attaque n'a rien d'improvisé. Elle a été planifiée et exécutée avec une précision opérationnelle que plusieurs chercheurs qualifient de remarquable.
30 mars 2026, 05:57 UTC — L'attaquant publie [email protected] sur le registre npm sous le compte nrwise (email : [email protected]). Cette version est propre : c'est une copie quasi identique de la bibliothèque légitime crypto-js, sans aucun code malveillant. Le but est de donner au paquet un historique de publication crédible, de le faire indexer par les miroirs npm et les couches CDN, et d'éviter les alertes automatiques qui se déclenchent sur les paquets tout neufs.
30 mars 2026, 23:59:12 UTC — Dix-huit heures plus tard, l'attaquant publie [email protected]. Cette fois, le paquet contient la charge utile malveillante : un script setup.js obfusqué qui sert de dropper pour un RAT multi-plateforme.
31 mars 2026, 00:05:41 UTC — Le scanner automatisé de Socket détecte le paquet malveillant, six minutes après sa publication. L'alerte est émise.
31 mars 2026, 00:21 UTC — L'attaquant publie [email protected] en utilisant le compte npm compromis du mainteneur principal d'Axios, jasonsaayman. La publication est faite manuellement via le CLI npm, contournant complètement le pipeline CI/CD GitHub Actions et les attestations de provenance SLSA qui protègent normalement les versions légitimes.
31 mars 2026, ~01:00 UTC — Environ 39 minutes plus tard, l'attaquant publie [email protected], ciblant la branche héritée 0.x. Les deux branches majeures d'Axios sont désormais compromises.
31 mars 2026, ~03:29 UTC — Les versions malveillantes sont retirées du registre npm. La fenêtre d'exposition totale est d'environ trois heures.
Le système de détection comportementale de StepSecurity a identifié la publication anormale en 14 minutes. Le chercheur en sécurité @mvxvvll a été le premier à donner l'alerte publique. Feross Aboukhadijeh, PDG de Socket, a confirmé l'attaque active sur X.
Comment le compte du mainteneur a été compromis
L'attaquant a obtenu un token d'accès npm classique à longue durée de vie appartenant au compte jasonsaayman, le mainteneur principal d'Axios. Ce type de token, une fois en possession de l'attaquant, permet de publier n'importe quel paquet sous ce compte sans aucune autre forme d'authentification.
Une fois le token obtenu, l'attaquant a changé l'adresse email associée au compte npm de jasonsaayman, passant de l'email légitime ([email protected]) à une adresse Proton Mail anonyme ([email protected]). Cette manœuvre classique de prise de contrôle de compte verrouille le mainteneur légitime hors des flux de récupération de compte, tout en donnant à l'attaquant le contrôle total sur les vérifications futures et les réinitialisations d'authentification à deux facteurs.
Le point critique à retenir : le registre npm traite un token valide comme l'unique frontière d'authentification pour la publication. Un token suffit pour contourner toutes les protections : les revues de code, les pipelines CI/CD, les protections de branche et les workflows de release tagués.
Anatomie technique de l'attaque
L'injection : une seule ligne dans package.json
La sophistication de cette attaque réside dans sa discrétion. Aucun fichier source d'Axios n'a été modifié. La seule modification apportée au package.json des deux versions compromises consistait à ajouter une dépendance :
"plain-crypto-js": "4.2.1"
Et à supprimer le script prepare (qui exécute les hooks Git de Husky), pour éviter des erreurs lors de la publication manuelle.
En temps normal, Axios ne possède que trois dépendances : follow-redirects, form-data et proxy-from-env. L'ajout de plain-crypto-js est un signe de falsification sans ambiguïté — mais seulement si quelqu'un pense à vérifier.
Le dropper : setup.js et sa double couche d'obfuscation
Lorsqu'un développeur ou un système CI/CD exécute npm install [email protected], le moteur de résolution de dépendances de npm récupère automatiquement [email protected] comme dépendance transitive. Le hook postinstall de ce paquet déclenche alors node setup.js.
Ce fichier de 4 209 octets est un dropper obfusqué utilisant un schéma d'encodage en deux couches spécialement conçu pour échapper à l'analyse statique et à la détection par signatures :
Couche 1 — Base64 inversé : La chaîne encodée est inversée, les underscores sont remplacés par des caractères de padding =, et le résultat est décodé en Base64.
Couche 2 — Chiffrement XOR : Chaque caractère décodé est soumis à un XOR avec un chiffre de la clé OrDeR_7077 (sélectionné par l'indice 7*i*i % 10) et la constante 333.
Les 18 chaînes obfusquées dans le tableau stq[] — incluant les noms de modules, l'URL du serveur C2, les commandes shell et les chemins de fichiers — sont toutes masquées derrière cet encodage. Il ne s'agit pas de minification ou de protection de propriété intellectuelle : c'est un système d'obfuscation construit sur mesure pour cacher des indicateurs de malware aux scanners de sécurité.
Le branchement par système d'exploitation
Après déobfuscation, le script détecte le système d'exploitation via os.platform() et exécute une chaîne d'attaque spécifique à chaque plateforme. Trois payloads distincts ont été pré-construits :
macOS : Le dropper exécute un payload AppleScript qui télécharge un binaire RAT depuis le serveur C2 (sfrclak.com:8000), le sauvegarde sous /Library/Caches/com.apple.act.mond — un chemin délibérément similaire à un processus système légitime d'Apple — change ses permissions pour le rendre exécutable, et le lance en arrière-plan via /bin/zsh. Le fichier AppleScript est supprimé après exécution.
Windows : Le malware localise le chemin du binaire PowerShell, le copie vers %PROGRAMDATA%\wt.exe (se faisant passer pour l'application Windows Terminal), puis écrit un script VBScript dans le répertoire temporaire et l'exécute. Ce VBScript contacte le même serveur pour récupérer un script RAT PowerShell et l'exécuter.
Linux : Un RAT Python est téléchargé vers /tmp/ld.py et lancé comme processus orphelin en arrière-plan via nohup python3, le détachant de la session terminal qui l'a engendré.
Le serveur de commande et contrôle (C2)
Les trois plateformes communiquent avec le même serveur C2, mais envoient des corps POST distincts pour permettre au serveur de servir le payload approprié :
- macOS :
packages.npm.org/product0 - Windows :
packages.npm.org/product1 - Linux :
packages.npm.org/product2
Le domaine C2 est sfrclak.com, port 8000, avec l'adresse IP 142.11.206.73.
Le RAT : capacités et fonctionnement
Le binaire de deuxième étage pour macOS est un RAT écrit en C++ qui effectue une empreinte du système et envoie un beacon au serveur distant toutes les 60 secondes pour récupérer des commandes. Ses capacités incluent : l'exécution de payloads supplémentaires, l'exécution de commandes shell, l'énumération du système de fichiers, et la terminaison du RAT.
L'analyse de SafeDep a révélé que le RAT Linux possède les mêmes capacités que son homologue macOS. Fait notable : l'absence de mécanisme de persistance signifie que le malware ne survit pas aux redémarrages. Cela suggère que l'attaque vise soit l'exfiltration rapide de données, soit l'utilisation de la capacité du RAT à exécuter des binaires et des commandes shell pour déployer la persistance via d'autres moyens.
Des analyses d'Open Source Malware ont relevé que le RAT cible spécifiquement les répertoires .ssh et .aws, effectue du monitoring de processus et une reconnaissance extensive des systèmes infectés — des indicateurs qui pointent vers un acteur de type APT (Advanced Persistent Threat) faisant de la collecte de renseignements et du vol de credentials, plutôt que vers une attaque financièrement motivée.
L'auto-destruction : effacer les traces
Après exécution, le malware met en œuvre un mécanisme anti-forensique : le fichier setup.js est supprimé, et le package.json du paquet plain-crypto-js est remplacé par une version propre (en renommant package.md en package.json), supprimant la référence au hook postinstall. Un développeur qui inspecterait son dossier node_modules après coup ne trouverait aucune indication qu'un problème s'est produit.
La propagation secondaire
Socket a identifié deux paquets supplémentaires distribuant le même malware via des dépendances vendorées :
@shadanai/openclaw (versions 2026.3.28-2, 2026.3.28-3, 2026.3.31-1 et 2026.3.31-2) : ce paquet, un fork du gateway IA open source OpenClaw, embarque directement le payload malveillant plain-crypto-js dans un chemin vendoré profond. Le fichier setup.js est identique au paquet autonome — même obfuscation, même C2, mêmes payloads, même mécanisme d'auto-destruction.
@qqbrowser/[email protected] : ce paquet utilise un vecteur d'injection différent. Plutôt que d'embarquer plain-crypto-js directement, il intègre une version falsifiée d'[email protected] dans son node_modules/ avec plain-crypto-js injecté comme dépendance.
Ces paquets secondaires illustrent comment une seule dépendance compromise peut se propager en cascade à travers l'écosystème, particulièrement dans un contexte où les outils d'IA et les pipelines de build automatisés accélèrent le rythme de publication des paquets.
Les signaux d'alerte qui auraient pu (et qui ont) permis la détection
Plusieurs indicateurs trahissaient la nature malveillante des versions compromises :
Absence de tag GitHub : La version 1.14.1 n'a aucun tag correspondant dans le dépôt GitHub d'Axios. Le dernier tag légitime est v1.14.0, publié le 27 mars 2026.
Absence d'attestation de provenance SLSA : Les versions légitimes d'Axios sont publiées via GitHub Actions OIDC avec une attestation de provenance SLSA complète. Les versions malveillantes n'en ont aucune. Ce signal est considéré par plusieurs chercheurs comme l'indicateur de détection le plus fiable.
Changement de méthode de publication : Les métadonnées du registre npm montrent un passage d'une publication automatisée CI à une publication manuelle.
Changement d'email du compte : Le passage d'un email Gmail vers une adresse Proton Mail anonyme.
Nouvelle dépendance inconnue : L'ajout de plain-crypto-js, un paquet qui n'existait pas 24 heures auparavant et qui n'est importé nulle part dans le code source d'Axios.
Le contexte plus large : une escalade d'attaques supply chain
L'attaque sur Axios ne survient pas dans le vide. Elle s'inscrit dans une vague d'attaques supply chain de plus en plus sophistiquées qui frappent l'écosystème open source en 2026.
LiteLLM — une semaine plus tôt
Le 24 mars 2026, le groupe de menaces TeamPCP a compromis LiteLLM, la bibliothèque Python de passerelle IA universelle avec environ 97 millions de téléchargements mensuels. Les versions compromises 1.82.7 et 1.82.8 contenaient un voleur de credentials multi-étages capable de collecter les clés SSH, les credentials cloud, les secrets Kubernetes, les portefeuilles de cryptomonnaies et les fichiers .env.
L'attaque sur LiteLLM était elle-même le maillon d'une chaîne plus longue : TeamPCP avait d'abord compromis le scanner de sécurité Trivy d'Aqua Security (19 mars), puis les GitHub Actions de Checkmarx KICS (23 mars), avant d'utiliser les credentials récoltés dans le pipeline CI/CD de LiteLLM pour publier les versions empoisonnées sur PyPI.
Ce qui rend l'attaque LiteLLM particulièrement inquiétante, c'est le mécanisme utilisé : un fichier .pth (litellm_init.pth) qui s'exécute automatiquement à chaque démarrage de processus Python, même sans importer la bibliothèque. La personne qui a découvert l'attaque ne l'a trouvée que parce que son IDE Cursor l'a installée via un plugin MCP comme dépendance transitive.
La campagne Shai-Hulud 2.0
En décembre 2025, le ver Shai-Hulud 2.0 a volé environ 400 000 secrets de développeurs via des paquets npm infectés, utilisant aussi des scripts postinstall comme vecteur d'attaque. En septembre 2025, les paquets Chalk et Debug avaient été compromis suite à une attaque de phishing sur un compte de mainteneur — exactement la même tactique que celle utilisée dans l'attaque Axios.
Le précédent xz-utils
En mars 2024, la backdoor xz-utils avait démontré comment l'ingénierie sociale de mainteneurs pouvait compromettre des infrastructures critiques, posant les bases de cette nouvelle génération d'attaques.
Êtes-vous affecté ? Guide de vérification
Vérification rapide
Ouvrez votre terminal dans le répertoire de votre projet et exécutez :
npm ls axios
Si vous voyez [email protected] ou [email protected], vous avez été touché. Toute autre version signifie que vous n'êtes pas affecté par cette attaque spécifique.
Vérification approfondie
Recherchez les artefacts de persistance du RAT sur votre système :
- Toutes plateformes : Fichier
$TMPDIR/6202033 - macOS : Fichier
/Library/Caches/com.apple.act.mond - Windows : Fichier
%PROGRAMDATA%\wt.exe - Linux : Fichier
/tmp/ld.pyet fichiers cachés dans/tmp/préfixés par un point
Vérifiez également le trafic réseau sortant vers sfrclak.com ou l'adresse IP 142.11.206.73 sur le port 8000.
Si vous êtes affecté : mesures d'urgence
Considérez votre système comme compromis. Le RAT était actif, communiquait avec un serveur de commande et était capable d'exécuter des payloads arbitraires. Voici les étapes de remédiation :
- Rétrograder immédiatement vers
[email protected](branche 1.x) ou[email protected](branche 0.x) - Supprimer le répertoire
node_modules/plain-crypto-js - Réinstaller avec
npm install --ignore-scripts - Effectuer une rotation de tous les secrets : tokens npm, clés API, clés SSH, credentials cloud (AWS, GCP, Azure), tokens CI/CD, mots de passe de bases de données, tout ce qui était stocké ou accessible sur la machine
- Auditer les pipelines CI/CD pour identifier les exécutions qui ont installé les versions affectées
- Bloquer le trafic sortant vers le domaine C2 :
sfrclak.com, IP142.11.206.73, port8000, chemin URL/6202033 - Rechercher les fichiers inhabituels aux emplacements listés ci-dessus
- Pour les environnements à haut risque, envisager la reconstruction des conteneurs et le reprovisionnement de l'infrastructure
Comment se prémunir : les défenses qui fonctionnent
L'analyse post-mortem de cette attaque révèle que trois contrôles, tous disponibles aujourd'hui, auraient suffi à bloquer la compromission. Voici un guide complet de protection.
1. Verrouiller vos dépendances avec des lockfiles
Le lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml) épingle les versions exactes et inclut des hashes d'intégrité cryptographiques. Chaque installation vérifie que les paquets téléchargés correspondent au hash attendu.
Actions concrètes :
- Committez toujours votre lockfile dans votre dépôt Git
- Utilisez
npm ci(et nonnpm install) dans vos environnements CI/CD : cette commande installe exactement ce qui est défini dans le lockfile - Évitez les plages de version flexibles (
^,~,latest) pour vos dépendances critiques : elles peuvent tirer des versions non révisées sans prévenir - Un projet utilisant un range carets
^1.14.0aurait automatiquement résolu vers1.14.1lors du prochainnpm install— exactement ce que l'attaquant a exploité
2. Désactiver les scripts de cycle de vie (postinstall)
Les scripts postinstall sont le vecteur d'exécution de malware principal dans l'écosystème npm. L'attaque Axios, la campagne Shai-Hulud, et d'innombrables autres compromissions reposent toutes sur ce mécanisme.
Actions concrètes :
# Désactiver globalement les scripts de lifecycle
npm config set ignore-scripts true --global
# Ou par projet dans .npmrc
ignore-scripts=true
Avec pnpm v10, l'exécution automatique des scripts postinstall dans les dépendances est désactivée par défaut. pnpm recommande de lister explicitement uniquement les dépendances de confiance via allowBuilds, de sorte qu'une dépendance qui ne nécessitait pas de build auparavant ne puisse pas soudainement exécuter un script malveillant.
3. Vérifier la provenance des paquets
Les versions légitimes d'Axios sont publiées avec une attestation de provenance SLSA via GitHub Actions OIDC. L'absence de cette attestation sur les versions malveillantes est le signal de détection le plus fiable identifié dans cette attaque.
Actions concrètes :
- Vérifiez la provenance npm de vos paquets critiques : les paquets avec provenance affichent un badge vert sur npm
- Utilisez le trusted publishing via OpenID Connect (OIDC) plutôt que des tokens pour publier vos propres paquets
- Configurez vos outils pour alerter quand une version d'un paquet perd son attestation de provenance — c'est un signal d'alarme immédiat
4. Appliquer l'authentification multi-facteurs
L'attaquant a pu publier les versions malveillantes avec un simple token d'accès npm classique. L'application de l'authentification multi-facteurs (MFA) sur tous les comptes de mainteneurs npm, idéalement avec des clés matérielles (FIDO2) plutôt que TOTP, aurait empêché ou significativement compliqué cette attaque.
5. Ne pas se précipiter sur les mises à jour
Une nouvelle version n'est pas automatiquement une meilleure version. Accorder quelques jours à la communauté pour signaler les versions malveillantes ou cassées avant de mettre à jour réduit considérablement le risque d'exposition. Une période d'attente de 7 à 14 jours avant d'adopter de nouveaux paquets ou des mises à jour majeures aurait prévenu la plupart des attaques de 2025 et 2026 : les paquets malveillants sont typiquement détectés en quelques jours.
6. Générer et maintenir des SBOMs
Un inventaire logiciel (Software Bill of Materials) au format machine-readable (SPDX ou CycloneDX) pour tous vos déploiements en production permet de déterminer votre exposition en quelques minutes quand le prochain incident supply chain survient.
# Générer un SBOM avec npm
npm sbom --sbom-format cyclonedx
# Ou avec Syft pour une couverture complète
syft . -o cyclonedx-json > sbom.json
7. Utiliser des outils de surveillance continue de la supply chain
Des outils comme Socket, StepSecurity Harden-Runner, Snyk, Aikido Safe Chain, ou Datadog SCFW surveillent en continu les modifications de paquets et corrèlent les changements avec la threat intelligence en temps réel. Dans le cas d'Axios, Socket a détecté le paquet malveillant en six minutes et StepSecurity en 14 minutes.
8. Isoler les environnements de build
Les scripts postinstall s'exécutent avec les pleins privilèges du développeur. Utilisez des environnements isolés (conteneurs, VMs) pour les installations de dépendances, limitez l'accès réseau sortant depuis les environnements de build, et séparez les credentials des environnements où les installations de paquets se produisent.
9. Auditer le trafic réseau sortant
Enregistrez et surveillez les connexions réseau sortantes depuis vos pipelines CI/CD et vos environnements de développement. Le callback C2 vers sfrclak.com:8000 a été signalé comme anormal par StepSecurity Harden-Runner parce qu'il n'était jamais apparu dans aucune exécution de workflow antérieure. Ce type de détection comportementale est essentiel pour repérer les menaces zero-day.
10. Protections spécifiques pour les utilisateurs d'outils IA
L'ère du « vibe coding » où les outils d'IA installent des paquets de manière autonome amplifie le risque supply chain. Si vous utilisez des outils comme Cursor, Claude Code, GitHub Copilot ou d'autres assistants IA pour le développement :
- Ne laissez jamais un outil IA exécuter
npm installsans vérification - Revoyez les suggestions de dépendances avant de les accepter
- Vérifiez que vos outils IA respectent votre lockfile et vos politiques de sécurité
- Rappelez-vous que les dépendances transitives — celles installées silencieusement comme dépendances de dépendances — sont le vecteur exploité dans cette attaque
Ce que cette attaque nous apprend
Cette attaque est qualifiée par StepSecurity comme l'une des plus opérationnellement sophistiquées jamais documentées contre un paquet npm du top 10. La dépendance malveillante a été préparée 18 heures à l'avance. Trois payloads séparés ont été pré-construits pour trois systèmes d'exploitation. Les deux branches de release ont été touchées en 39 minutes. Chaque trace a été conçue pour s'auto-détruire.
Et pourtant, trois contrôles — des lockfiles épinglés, la vérification de provenance et le blocage des scripts postinstall — auraient suffi à l'arrêter.
La leçon n'est pas de cesser d'utiliser npm ou de se méfier de toutes les dépendances. C'est de comprendre quels contrôles de supply chain auraient détecté cette attaque et de les mettre en place avant la prochaine. Car il y aura une prochaine. La question n'est plus de savoir si la confiance existe dans la chaîne d'approvisionnement logicielle, mais si cette confiance peut être prouvée, surveillée et révoquée quand elle échoue.
Indicateurs de compromission (IOCs)
| Indicateur | Valeur |
|---|---|
| Versions Axios compromises | 1.14.1, 0.30.4 |
| Paquet malveillant | [email protected] |
| Domaine C2 | sfrclak.com |
| IP C2 | 142.11.206.73 |
| Port C2 | 8000 |
| Chemin URL | /6202033 |
| Email attaquant (axios) | [email protected] |
| Email attaquant (plain-crypto-js) | [email protected] |
| Artefact macOS | /Library/Caches/com.apple.act.mond |
| Artefact Windows | %PROGRAMDATA%\wt.exe |
| Artefact Linux | /tmp/ld.py |
| SHA256 payload Linux | fcb81618bb15edfdedfb638b4c08a2af9cac9ecfa551af135a8402bf980375cf |
| Clé XOR d'obfuscation | OrDeR_7077 |