Vincent Strubel, directeur général de l’Agence nationale de la sécurité des systèmes d’information a évoqué hier dans son discours inaugural au Forum Incyber à Lille (du 31 mars au 2 avril) le piratage d’Axios pour souligner la fragilité du monde IT. Il faisait référence à la compromission du compte npm du principal mainteneur d’Axios un client HTTP JavaScript largement utilisé. Avec près de 175 000 projets npm qui se servent d’Axios comme dépendance, l’attaque a eu un effet domino.
Les pirates ont déployé des versions malveillantes du paquet pour exécuter un cheval de Troie d’accès à distance multiplateforme sur les machines des développeurs. Cet incident représente l’attaque le plus importante jamais enregistré contre npm, compte tenu des quelque 100 millions de téléchargements hebdomadaires d'Axios et de sa présence dans les frameworks frontend, les services backend et d'innombrables applications d'entreprise.
Une affiliation avec la Corée du Nord
Heureusement, les versions infectées, axios@1.14.1 et axios@0.30.4, ont été détectées par plusieurs sociétés de sécurité surveillant le registre npm quelques minutes après leur publication. Grâce à une intervention rapide, l'équipe npm a supprimé les paquets malveillants deux à trois heures plus tard. Cela étant dit, compte tenu du volume important de téléchargements de ce projet, le court laps de temps imparti a suffi à impacter un nombre significatif d'environnements de développement. Selon Wiz, Axios sert dans 80 % des environnements cloud et de code ; l'entreprise a observé l'exécution du malware dans environ 3 % des environnements touchés. Les chercheurs de Snyk ont noté que « même une fenêtre d'action malveillante de deux heures représente un potentiel de propagation énorme » étant donné la popularité de la bibliothèque.
Cette campagne fait suite à une série d'attaques de la supply chain ayant affecté de nombreux projets open source sur différents dépôts de paquets au cours des dernières semaines, la plupart étant attribuées à un groupe connu sous le nom de TeamPCP. Cependant, la division de renseignements sur les menaces de Google (GTIG) a attribué l'attaque contre Axios à un acteur de la menace nord-coréen qu'il surveille sous le nom de UNC1069. « Les pirates informatiques nord-coréens possèdent une solide expérience des attaques de la supply chain, qu'ils ont historiquement utilisées pour voler des cryptomonnaies », a déclaré John Hultquist, analyste principal chez GTIG. « L'ampleur exacte de cet incident reste encore floue, mais compte tenu de la popularité du paquet compromis, nous prévoyons des répercussions considérables. » Dans leur analyse, les chercheurs de Snyk ont également souligné la sophistication des techniques employées lors de l'attaque.
Déroulement de l'attaque
Les pirates ont commencé à préparer l'attaque contre Axios environ 18 heures auparavant, lorsqu'un compte nommé nrwise a publié un paquet appelé plain-crypto-js@4.2.0. Il s'agissait d'un leurre conçu pour établir l'historique du registre et sa légitimité. Le code malveillant est apparu plus tard dans la journée dans plain-crypto-js@4.2.1, qui contenait un hook post-installation exécutant un script d'installation malveillante lorsqu'il était importé comme dépendance par un autre paquet. Peu après minuit UTC le 31 mars, une nouvelle version du paquet Axios, axios@1.14.1, a été publiée sur npm, suivie 39 minutes plus tard par axios@0.30.4. Ces deux versions listaient plain-crypto-js@4.2.1 comme dépendance dans leur fichier package.json, mais le reste des composants est resté inchangé.
Quelques indices ont alerté les experts en cybersécurité. Le paquet malveillant représente une dépendance fantôme, car il est ni utilisé, ni importé dans le code source, ce qui constitue un IoC (indice de compromission) fiable, selon les chercheurs de StepSecurity. Autre élément, ces versions n'apparaissaient que sur npm et non dans le dépôt GitHub du projet en tant que versions étiquetées. Les versions 1.x officielles d'Axios étaient configurées pour utiliser le mécanisme de publication de confiance Oidc (OpenID Connect) de npm, lié à GitHub Actions. Cependant, la version 1.14.1 a été publiée manuellement à l'aide d'un token volé, sans commit ni tag correspondant dans le dépôt. Dans les commentaires sur GitHub, Jason Saayman, le principal mainteneur du projet, a reconnu que si la version 1.x disposait d'une configuration de publication de confiance, la branche 0.x reposait encore sur un token persistant obsolète. Un membre de la communauté a également souligné que le flux de publication de la version 1.x transmettait toujours NODE_AUTH_TOKEN à npm, lequel est prioritaire sur Oidc lorsque les deux sont présents. Cela signifie que le token persistant était également utilisé pour la version 1.x au lieu du mécanisme de publication de confiance prévu.
Une charge multiplateformes
Le script post-installation, obfusqué et chiffré, contacte un serveur de commande et de contrôle (C2) sur un domaine enregistré la veille par les attaquants et télécharge des charges utiles RAT de deuxième niveau spécifiques à chaque plateforme. Sous macOS, le binaire est enregistré dans /Library/Caches/com.apple.act.mond et peut auto-signer les charges utiles injectées via la commande `cosign --force --deep --sign`, contournant ainsi les protections Gatekeeper de macOS. Le malware identifie le système, collecte le nom d'hôte, le nom d'utilisateur, la version de macOS, les heures de démarrage et d'installation, l'architecture du processeur et les processus en cours d'exécution, puis contacte le serveur C2 toutes les 60 secondes.
Sous Windows, la charge utile est un script PowerShell copié dans %PROGRAMDATA%\wt.exe, se faisant passer pour le Terminal Windows. Le malware assure sa persistance grâce à une clé de registre Run nommée « MicrosoftUpdate » et un fichier batch de téléchargement. Sous Linux, un script Python stocké dans /tmp/ld.py est exécuté via la commande `nohup python3`. Le RAT prend en charge quatre commandes : `peinject` pour déployer des binaires supplémentaires, `runscript` pour exécuter du code shell ou AppleScript, `rundir` pour l’énumération des répertoires et `kill` pour l’autodestruction. Selon les chercheurs de Socket, après son exécution, le logiciel tente d’effacer ses traces en supprimant `setup.js`, en éliminant le fichier `package.json` malveillant contenant le hook `postinstall` et en le remplaçant par une copie saine indiquant la version 4.2.0 au lieu de 4.2.1. Ainsi, les utilisateurs exécutant `npm list` dans un répertoire de projet affecté verront `plain-crypto-js@4.2.0`, ce qui pourrait les induire en erreur et leur faire croire que la version installée est antérieure à l’attaque.
La sécurité fragile des projets open source
Les sociétés de sécurité surveillant npm ont signalé `plain-crypto-js@4.2.1` quelques minutes après sa publication, déclenchant une série de réactions, notamment de la part de l’équipe du registre npm qui a supprimé les paquets. Cependant, le projet Axios lui-même a eu des difficultés à contenir le problème car l’incident s’est produit pendant les heures de travail nocturnes du responsable principal. Un collaborateur clé du projet a également répondu en quelques minutes au problème signalé par la communauté sur GitHub, mais ses permissions étaient inférieures à celles du mainteneur dont le token a été compromis. Ceci souligne une faille potentielle dans la réponse aux incidents à laquelle les projets open source peuvent être confrontés. En effet, même si les contributeurs du projet détectent immédiatement une brèche, l'attaquant pourrait disposer de privilèges plus élevés grâce à un token volé, ce qui pourrait ralentir les efforts de limitation des dégâts. Lors de la récente compromission de Trivy, les attaquants ont inondé le problème GitHub de commentaires indésirables envoyés par des bots afin de rendre plus difficile la réponse des mainteneurs et la communication avec la communauté.
L'effet domino de l'incident Axios est devenu visible lorsque les outils d'analyse des dépendances ont signalé des centaines de projets en aval ayant récupéré les versions malveillantes. Un utilisateur a publié des avertissements concernant plus de 50 dépôts après avoir détecté plain-crypto-js dans leurs fichiers de verrouillage, tandis qu'un autre en a identifié des dizaines d'autres, allant de blogs personnels à des applications d'entreprise. Cela démontre la rapidité avec laquelle la compromission d'un paquet npm populaire se propage dans l'écosystème, même si la faille est détectée en quelques heures.
Réinstaller les systèmes compromis
Les organisations doivent immédiatement auditer les fichiers de verrouillage et les dépendances installées afin de détecter les versions compromises. Si de telles versions sont installées, considérez que les environnements de développement sont entièrement touchés. Les équipes de sécurité doivent isoler les systèmes affectés et renouveler tous les identifiants présents, tels que les jetons npm, les clés de fournisseur cloud, les clés privées SSH, les secrets CI/CD, etc. « Ne procédez pas à un renouvellement sur place ; révoquez et réémettez les identifiants », conseillent les chercheurs de Snyk. « N'essayez pas de nettoyer les systèmes compromis. Reconstruisez-les à partir d'un instantané sain connu.»
À long terme, les organisations devraient imposer l'option `--ignore-scripts` de npm dans les pipelines CI/CD afin d'empêcher l'exécution des hooks post-installation lors des builds automatisés et envisager des politiques de durée de vie des paquets, telles que le paramètre `minimumReleaseAge` de npm. Cela donne aux équipes de développement la capacité de bloquer l'installation des paquets sans ancienneté minimale, ce qui aurait empêché cette attaque puisque « plain-crypto-js » existait depuis moins de 24 heures avant d'être intégré à l'arbre de dépendances d'Axios. La vigilance est de mise aussi sur les outils IA comme Claude Code d’Anthropic et Codex d’OpenAI qui s’appuient fortement sur les écosystèmes npm et PyPI pour les outils en ligne de commande.