- Deux versions malveillantes du très utilisé client HTTP axios ont été publiées sur npm et déploient, lors de l’installation, un cheval de Troie d’accès à distance (RAT)
- L’attaquant a contourné GitHub Actions et téléversé manuellement les paquets malveillants après avoir volé les identifiants du compte du mainteneur
- Les versions malveillantes incluaient une fausse dépendance
plain-crypto-js@4.2.1 qui installait le RAT via un script postinstall puis effaçait ses traces
- Le RAT infecte macOS, Windows et Linux, communique avec le serveur C2 (
sfrclak.com:8000) et télécharge des charges utiles supplémentaires
- npm et GitHub ont rapidement supprimé les versions malveillantes, mais l’incident remet en lumière l’importance du renforcement de la sécurité de la supply chain et de la protection des identifiants
Vue d’ensemble de l’attaque sur la supply chain npm d’axios
- Le 31 mars 2026, deux versions malveillantes de la très utilisée bibliothèque cliente HTTP axios (
axios@1.14.1, axios@0.30.4) ont été publiées sur npm
- L’attaquant a volé les identifiants npm d’un mainteneur principal d’axios, contourné le pipeline CI/CD GitHub Actions et publié manuellement les paquets malveillants
- Les deux versions inséraient une fausse dépendance,
plain-crypto-js@4.2.1, dont le script postinstall installait un cheval de Troie d’accès à distance (RAT)
- Le RAT vise macOS, Windows et Linux, et communique avec le serveur C2 (Command and Control)
sfrclak.com:8000 pour télécharger une charge utile de deuxième étape
- Après l’installation, le code malveillant supprime ses fichiers et remplace le
package.json par une version propre afin d’échapper à la détection forensique
Chronologie de l’attaque
- 30 mars 05:57 UTC : publication de
plain-crypto-js@4.2.0 (version légitime)
- 30 mars 23:59 UTC : publication de
plain-crypto-js@4.2.1 (version malveillante), avec ajout d’un hook postinstall
- 31 mars 00:21 UTC : publication de
axios@1.14.1, avec insertion de la dépendance malveillante
- 31 mars 01:00 UTC : publication de
axios@0.30.4, avec la même dépendance malveillante
- 31 mars 03:15 UTC : npm supprime les deux versions malveillantes
- 31 mars 04:26 UTC : npm remplace
plain-crypto-js par un stub de protection de sécurité (0.0.1-security.0)
Présentation d’axios
- axios est le client HTTP le plus largement utilisé dans l’écosystème JavaScript, aussi bien côté Node.js que dans le navigateur
- Avec plus de 300 millions de téléchargements hebdomadaires, une seule release malveillante peut avoir un impact à très grande échelle
- Pour un développeur classique, il est difficile de remarquer l’installation de code malveillant lors d’un
npm install
Étapes de l’attaque
-
Étape 1 — Compromission du compte du mainteneur
- L’attaquant a compromis le compte npm
jasonsaayman et changé l’adresse e-mail en ifstap@proton.me
- Il a ensuite publié des builds malveillants sur les branches de release 1.x et 0.x
- Les releases légitimes sont publiées via OIDC Trusted Publisher de GitHub Actions, mais
axios@1.14.1 a été publié manuellement, sans gitHead ni signature OIDC
- L’attaquant est soupçonné d’avoir utilisé un token d’accès npm à longue durée de vie
-
Étape 2 — Pré-déploiement de la dépendance malveillante
plain-crypto-js@4.2.1 a été publié depuis le compte nrwise@proton.me
- Le paquet usurpe
crypto-js en réutilisant la même description et l’URL du dépôt
- Il contient le hook
"postinstall": "node setup.js", exécuté automatiquement à l’installation
- Après l’attaque,
package.md est remplacé par package.json afin de préparer l’effacement des preuves
-
Étape 3 — Injection de la dépendance dans axios
plain-crypto-js@^4.2.1 est ajouté comme dépendance d’exécution
- Le code ne l’importe jamais → dépendance fantôme
- Lors d’un
npm install, elle est installée automatiquement et exécute le script postinstall
Analyse du dropper RAT (setup.js)
-
Techniques d’obfuscation
- Les chaînes sont stockées de façon chiffrée dans le tableau
stq[] puis déchiffrées via _trans_1 (XOR) et _trans_2 (Base64 + inversion)
- L’URL du C2 est
http://sfrclak.com:8000/6202033
- Les chaînes déchiffrées incluent des identifiants d’OS (
win32, darwin), des chemins de fichiers et des commandes shell
-
Charges utiles selon la plateforme
-
macOS
- Un AppleScript est écrit dans
/tmp puis exécuté via osascript
- Le binaire RAT est récupéré depuis le C2, enregistré dans
/Library/Caches/com.apple.act.mond, puis exécuté
- Le nom du fichier imite un daemon système Apple
-
Windows
- Le chemin de PowerShell est recherché puis le fichier est copié vers
%PROGRAMDATA%\wt.exe
- Un VBScript télécharge et exécute depuis le C2 un RAT PowerShell
- Les fichiers temporaires (
.vbs, .ps1) sont supprimés après exécution
-
Linux
curl télécharge /tmp/ld.py, puis celui-ci est lancé avec nohup python3
- Le fichier
/tmp/ld.py reste présent
- Sur les trois plateformes, le corps POST envoyé à
packages.npm.org/product0~2 sert à imiter un trafic npm légitime
-
Auto-suppression et dissimulation
setup.js et package.json sont supprimés
package.md est remplacé par package.json afin de faire passer le paquet pour légitime
- Ensuite, ni
npm audit ni une revue manuelle ne permettent de le détecter
- En revanche, la présence de
node_modules/plain-crypto-js/ constitue en elle-même une preuve d’infection
Validation de l’exécution avec StepSecurity Harden-Runner
- Harden-Runner journalise en temps réel les événements réseau, processus et fichiers dans GitHub Actions
- Lors de l’installation de
axios@1.14.1, deux connexions au C2 (curl, nohup) ont été détectées
- La première a eu lieu 2 secondes après le début de
npm install
- La seconde, 36 secondes plus tard, s’est poursuivie via un processus en arrière-plan
- L’analyse de l’arbre des processus montre que le processus
nohup, devenu orphelin sous PID 1 (init), continue de s’exécuter durablement
- Les journaux d’événements fichiers montrent que
package.json a été réécrit deux fois
- Première fois : écriture de la version malveillante pendant l’installation
- Deuxième fois : 36 secondes plus tard, remplacement par un stub propre
Indicateurs de compromission (IOC)
-
Paquets npm malveillants
- axios@1.14.1 · shasum : 2553649f232204966871cea80a5d0d6adc700ca
- axios@0.30.4 · shasum : d6f3f62fd3b9f5432f5782b62d8cfd5247d5ee71
- plain-crypto-js@4.2.1 · shasum : 07d889e2dadce6f3910dcbc253317d28ca61c766
-
Réseau
-
Chemins de fichiers
- macOS :
/Library/Caches/com.apple.act.mond
- Windows :
%PROGRAMDATA%\wt.exe
- Linux :
/tmp/ld.py
-
Comptes attaquants
jasonsaayman (mainteneur compromis)
nrwise (compte créé par l’attaquant)
-
Version sûre
Vérification d’impact et procédure de réponse
- Vérifier dans
npm list axios ou package-lock.json la présence de 1.14.1 / 0.30.4
- Vérifier l’existence de
node_modules/plain-crypto-js
- Si les fichiers RAT sont présents selon l’OS, considérer le système comme totalement compromis
- Vérifier dans les logs CI/CD si ces versions ont été installées, puis remplacer tous les secrets et tokens
Étapes de remédiation
- Épingler axios sur une version sûre (
1.14.0 ou 0.30.3)
- Supprimer le dossier
plain-crypto-js, puis réinstaller avec npm install --ignore-scripts
- En cas de traces du RAT, reconstruire le système
- Faire tourner toutes les informations d’identification (AWS, SSH, CI/CD, etc.)
- Auditer le pipeline CI/CD et remplacer les secrets
- Utiliser l’option
--ignore-scripts lors des builds automatisés
- Bloquer le domaine/l’IP du C2 via le pare-feu ou
/etc/hosts
Fonctionnalités StepSecurity Enterprise
-
Harden-Runner
- Application d’une liste blanche des sorties réseau dans GitHub Actions
- Blocage des trafics anormaux et journalisation
- Possibilité de bloquer en amont la connexion à
sfrclak.com:8000
-
Dev Machine Guard
- Supervision en temps réel des paquets npm installés sur les PC des développeurs
- Détection immédiate des machines ayant installé
axios@1.14.1 ou 0.30.4
-
npm Package Cooldown Check
- Application d’une période temporaire de blocage d’installation sur les nouveaux paquets publiés
- Permet de détecter des publications malveillantes rapides comme
plain-crypto-js@4.2.1
-
Compromised Updates Check
- Blocage des merges de PR à partir d’une base de données temps réel de paquets malveillants
axios@1.14.1 et plain-crypto-js@4.2.1 y sont ajoutés immédiatement
-
Package Search
- Recherche dans l’ensemble des PR et dépôts d’une organisation pour localiser où un paquet est introduit
- Permet d’identifier immédiatement le périmètre d’impact (dépôts, équipes, PR)
-
AI Package Analyst
- Surveillance en temps réel du registre npm et détection comportementale des paquets malveillants
- Les deux versions malveillantes ont été détectées quelques minutes après leur publication
-
Threat Center Alert
- Fournit des alertes de threat intel incluant résumé de l’attaque, IOC et procédure de réponse
- Offre une visibilité en temps réel via l’intégration SIEM
Remerciements
- Les mainteneurs d’axios et la communauté ont réagi rapidement via la GitHub issue #10604
- GitHub a suspendu le compte compromis et npm a supprimé les versions malveillantes tout en appliquant le security holder
- La réponse coordonnée entre mainteneurs, GitHub et npm a permis de limiter les dégâts pour les développeurs du monde entier
2 commentaires
Je n’aurais jamais pensé qu’un package de cette taille puisse se faire compromettre, mais axios dépasse l’imagination.
Avis sur Hacker News
npm, bun, pnpm et uv prennent désormais tous en charge la définition d’un âge minimal de publication des paquets
J’ai ajouté
ignore-scripts=truedans~/.npmrc, et ce seul réglage aurait déjà permis d’atténuer la vulnérabilitébun et pnpm n’exécutent pas les scripts de cycle de vie par défaut
Voici des exemples de configuration selon le gestionnaire de paquets :
exclude-newer = "7 days"min-release-age=7minimum-release-age=10080minimumReleaseAge = 604800Fait intéressant, les unités de temps diffèrent selon chacun
Si vous utilisez des agents LLM, ce réglage peut provoquer des échecs ; il faut donc ajouter des consignes à ce sujet dans
AGENTS.mdouCLAUDE.mdtimeoutMinutesau lieu detimeoutmin-release-age=7 # dayspourrait donc ne pas être appliqué comme prévunpmMinimalAgeGate: "3d"dans~/.yarnrc.ymlLa nouvelle selon laquelle Axios a été exposé à une attaque de la chaîne d’approvisionnement a choqué
Axios lui-même ne contenait pas de code malveillant, mais une fausse dépendance,
plain-crypto-js@4.2.1, a été injectée pour exécuter un script postinstall installant un RAT (cheval de Troie d’accès à distance)C’est une bonne nouvelle pour les utilisateurs qui, comme avec pnpm ou bun, doivent approuver manuellement les scripts postinstall
Selon certains, les gestionnaires de paquets sont une expérience ratée
Il existe des bibliothèques C de grande qualité, comme SQLite, constituées d’un unique fichier
.c, et cette approche permettrait d’éviter le problème des transitive dependenciesLa majeure partie de la surface d’attaque vient de ces dépendances indirectes
Même OpenSSL est en cours de réécriture à cause de problèmes de qualité de code, et JavaScript souffre d’une prolifération des polyfills parce qu’il est difficile d’étendre la bibliothèque standard
À la place, il a été proposé de renforcer les critères de qualité sur des dépôts comme npm et de n’y autoriser que des mainteneurs responsables
Une blague disait que certains commencent leur journée par un salut désabusé : « Quel paquet npm s’est encore fait compromettre aujourd’hui ? »
Pour les utilisateurs Linux, il a été recommandé d’utiliser bwrap afin de sandboxer toute la logique de build de npm, pip, cargo, gradle, etc.
bwrap fournit un environnement isolé comme Docker, mais sans nécessiter d’image. Flatpak repose sur la même technologie
En déploiement serveur, le durcissement des conteneurs est essentiel, et le point clé consiste à traiter l’environnement CI/CD comme une zone non fiable
Le même sandbox pourrait aussi être utilisé pour l’exécution d’IA
requiredans le code peut aussi déclencher une exécutionEn voyant sans cesse revenir les problèmes de dépendances, certains s’inquiètent de voir l’écosystème Rust connaître un jour des problèmes similaires
Il est difficile de faire grossir démesurément la bibliothèque standard, mais il faut un mécanisme fiable de garantie de qualité des paquets
Grâce à l’IA, ce travail supplémentaire devient plus faisable, et certains ont reconnu qu’ils auraient dû procéder ainsi depuis longtemps
Règles essentielles pour minimiser l’exposition aux attaques de la chaîne d’approvisionnement sur NPM
--frozen-lockfileoffrent déjà une protection suffisanteÀ la question « comment éviter complètement ce type d’attaque ? »,
certains ont répondu qu’ils aimeraient passer à Qubes OS pour séparer totalement le gestionnaire de mots de passe et l’environnement de build
Ils ont comparé cela aux équipements de protection individuelle (EPI) d’un laboratoire de chimie : l’environnement de développement aussi a besoin d’isolation et de protection
pip commence déjà à bloquer les installations hors virtualenv, et ils espèrent que les gestionnaires de paquets proposeront à l’avenir une option refusant l’exécution hors sandbox
pnpm et bun ignorent désormais les scripts postinstall par défaut, mais npm continue de les exécuter
Il est recommandé de définir
ignore-scripts=truedans~/.npmrcnpm totalise encore 80 millions de téléchargements par semaine
Certains supposent que la fuite d’identifiants à l’origine de cet incident pourrait provenir d’un précédent incident lié à LiteLLM
L’usage de Python ou de Node.js paraît inquiétant, mais cela semble en réalité être un problème général
« Quel paquet npm s’est encore fait compromettre aujourd’hui ? »