12 points par GN⁺ 2026-03-31 | 2 commentaires | Partager sur WhatsApp
  • 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

    • axios@1.14.0 (légitime)

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

  1. Épingler axios sur une version sûre (1.14.0 ou 0.30.3)
  2. Supprimer le dossier plain-crypto-js, puis réinstaller avec npm install --ignore-scripts
  3. En cas de traces du RAT, reconstruire le système
  4. Faire tourner toutes les informations d’identification (AWS, SSH, CI/CD, etc.)
  5. Auditer le pipeline CI/CD et remplacer les secrets
  6. Utiliser l’option --ignore-scripts lors des builds automatisés
  7. 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

 
chanapple 2026-03-31

Je n’aurais jamais pensé qu’un package de cette taille puisse se faire compromettre, mais axios dépasse l’imagination.

 
GN⁺ 2026-03-31
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=true dans ~/.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 :

    • uv : exclude-newer = "7 days"
    • npm : min-release-age=7
    • pnpm : minimum-release-age=10080
    • bun : minimumReleaseAge = 604800
      Fait 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.md ou CLAUDE.md
    • À la remarque « les unités de temps sont toutes différentes », quelqu’un a répondu en plaisantant : « C’est votre premier jour avec JavaScript ? »
    • pnpm a été le premier à introduire cette fonctionnalité. npm ne la prend en charge qu’à partir de la version 11.10.0, disponible depuis la release du 11 février 2026
    • Certains ont estimé qu’il vaudrait mieux expliciter l’unité dans le nom du paramètre de configuration, par exemple timeoutMinutes au lieu de timeout
    • npm ne prend peut-être pas en charge les commentaires. min-release-age=7 # days pourrait donc ne pas être appliqué comme prévu
    • Dans yarn berry, il est possible de définir npmMinimalAgeGate: "3d" dans ~/.yarnrc.yml
  • La 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

    • Dans Node.js, fetch n’est inclus par défaut qu’à partir de la v18, et sa stabilisation ne date que de la v21. Axios existe depuis bien plus longtemps et reste très utilisé, car il est intégré à de nombreux frameworks et tutoriels
    • À l’affirmation « les utilisateurs de pnpm/bun sont en sécurité », quelqu’un a objecté qu’ils avaient sans doute déjà approuvé ces scripts dans des versions précédentes
    • Une question a été posée sur le fait de savoir si pnpm bloque aussi les postinstall des dépendances transitives
  • 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 dependencies
    La majeure partie de la surface d’attaque vient de ces dépendances indirectes

    • Les gestionnaires de paquets sont désormais indispensables à l’adoption d’un langage. Le vrai problème est l’absence de contrôle qualité et la structure des incitations
      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
    • Certains ont aussi estimé qu’« une solution qui demande un peu plus d’effort ne sera pas acceptée par la communauté »
      À 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
    • En développement web, la surface d’attaque est bien plus large. La copie manuelle rend le suivi des mises à jour difficile, si bien que les fonctions d’alerte des gestionnaires de paquets restent utiles
    • D’après certains, NPM est un écosystème particulièrement touché par les attaques de la chaîne d’approvisionnement
    • D’autres ont rétorqué que Rust est plus sûr que C et que la plupart des crates sont de haute qualité, jugeant exagéré l’argument en faveur des bibliothèques C
  • 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

    • Mais certains ont souligné que cette méthode n’est efficace que contre les attaques via postinstall. Un simple require dans le code peut aussi déclencher une exécution
    • Quelqu’un a aussi créé amazing-sandbox, un sandbox personnel basé sur Docker
    • drop, un outil de plus haut niveau que bwrap, a également été recommandé
    • D’autres ont estimé que firejail est un sandbox de sécurité plus flexible
    • Il a aussi été fait remarquer que le transfert de socket SSH autorise l’accès à la clé privée et n’apporte donc pas de bénéfice de sécurité, et qu’il vaut mieux utiliser des clés protégées par mot de passe
  • En 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

    • Il a été proposé que les gros paquets (comme Axios) exigent que plusieurs approbateurs MFA valident la publication
    • Certains prédisent aussi l’émergence de services commerciaux fournissant des dépendances vérifiées
    • Une autre idée consistait à copier directement les tests des dépendances dans sa propre base de code et à les soumettre à son propre processus de revue de code
      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

    • utiliser le mode zero-installs de Yarn
    • désactiver les scripts postinstall ou les vérifier avant exécution
    • si du code tiers est exécuté pendant le développement, ne le lancer que dans une VM ou un conteneur
    • lors de l’ajout d’un paquet, considérer la popularité comme un point positif, mais la fraîcheur des commits comme un point négatif, et examiner soi-même le code et l’historique des changements
    • vérifier l’ensemble de l’arbre de dépendances et réévaluer le niveau de confiance à chaque arrivée d’un nouveau développeur
    • certains pensent que le lockfile et l’option --frozen-lockfile offrent déjà une protection suffisante
    • d’autres suivent une philosophie simple mais forte : « j’évite juste les stacks à problèmes »
  • À 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

    • Une équipe effectue tous les travaux liés à NPM uniquement dans des conteneurs Apple, et prévoit de faire de même pour Python et Rust
      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
    • Quelqu’un a même expliqué qu’il n’installe jamais Node.js/npm sur son système. Il n’a jamais vu de cas où cela était absolument nécessaire
  • 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=true dans ~/.npmrc
    npm 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

    • La définition d’un âge minimal de publication aide, mais beaucoup disent qu’ils ont toujours peur de mettre à jour leurs dépendances
    • D’autres avancent que c’est l’incident Trivy, et non LiteLLM, qui serait la cause profonde
    • Il a aussi été proposé d’exécuter cela dans des conteneurs temporaires rootless afin de limiter l’ampleur des dégâts
  • « Quel paquet npm s’est encore fait compromettre aujourd’hui ? »