Paquets malveillants npm et PyPI : comprendre et se protéger
Par l'équipe Lysbor · publié le · 4 min de lecture
Une vulnérabilité est une erreur involontaire dans un composant. Un paquet malveillant est un piège posé exprès : un code conçu pour voler des secrets, installer une porte dérobée ou miner de la cryptomonnaie, publié sur un registre public comme npm ou PyPI. Pour une petite équipe, c'est aujourd'hui l'un des risques les plus directs, parce qu'il frappe au moment où un développeur tape npm install.
Une vulnérabilité, c'est une serrure mal conçue sur une porte que vous avez achetée. Un paquet malveillant, c'est un cambrioleur livré dans le carton, qui attend que vous l'ouvriez.
Comment ils arrivent chez vous
Le typosquatting. L'attaquant publie un paquet dont le nom ressemble à un paquet populaire, à une lettre près ou avec un tiret en plus. Une faute de frappe, une suggestion d'autocomplétion, une réponse d'assistant de code un peu trop créative, et le paquet est installé.
Le compte de mainteneur compromis. Plus redoutable : l'attaquant prend le contrôle du compte d'un mainteneur légitime, par hameçonnage par exemple, et publie une nouvelle version piégée d'un paquet que tout le monde utilise déjà. En septembre 2025, des bibliothèques npm très répandues comme chalk et debug ont ainsi reçu des versions malveillantes après l'hameçonnage de leur mainteneur. Quelques jours plus tard, le ver baptisé Shai-Hulud s'est propagé sur npm en volant les jetons de publication des développeurs infectés pour piéger leurs propres paquets.
La prise de contrôle longue durée. Le cas de xz-utils (CVE-2024-3094, découvert en mars 2024) a montré qu'un attaquant patient peut gagner la confiance d'un projet pendant des années avant d'y glisser une porte dérobée.
Les scripts d'installation. npm et PyPI permettent d'exécuter du code au moment de l'installation. Un paquet piégé n'a donc pas besoin d'être appelé par votre application : il agit sur le poste du développeur ou dans la CI, là où se trouvent les clés d'accès au cloud et les jetons de publication.
Pourquoi les outils classiques les voient mal
Les scanners de vulnérabilités s'appuient traditionnellement sur les CVE. Or un paquet malveillant ne reçoit généralement pas de CVE : il est retiré du registre et signalé dans des bases dédiées. L'OpenSSF (Open Source Security Foundation) maintient un flux de paquets malveillants dont les entrées, identifiées par le préfixe MAL-, sont publiées dans la base OSV. Un outil qui ne lit que les CVE passe à côté.
Autre difficulté : le délai. Un paquet piégé est souvent détecté et retiré en quelques heures ou quelques jours. Tout se joue sur les versions très récentes.
Les protections concrètes
1. Utiliser les lockfiles et des installations reproductibles
En CI, installez avec npm ci (et non npm install), pip install --require-hashes ou poetry install : seules les versions exactes du lockfile, vérifiées par empreinte, sont installées. Une nouvelle version piégée publiée ce matin n'entre pas automatiquement.
2. Imposer un âge minimum aux nouvelles versions
La plupart des paquets malveillants sont repérés dans leurs premiers jours. Refuser automatiquement toute version publiée depuis moins de quelques jours (trois à sept, selon votre tolérance) élimine une grande partie du risque pour un coût quasi nul. Les mises à jour de sécurité urgentes peuvent faire l'objet d'une exception explicite.
3. Vérifier chaque pull request qui ajoute ou met à jour une dépendance
Le bon moment pour bloquer un paquet piégé est avant la fusion. Une vérification automatique sur la pull request doit contrôler : paquet signalé comme malveillant, version trop récente, paquet interdit par votre politique. C'est le rôle de la garde de pull request de Lysbor, qui commente la PR et peut bloquer la fusion.
4. Limiter ce qu'un paquet peut voler
- Désactiver les scripts d'installation quand c'est possible (
npm ci --ignore-scriptspour les projets qui n'en ont pas besoin). - Ne jamais laisser de jetons à longue durée de vie dans les variables d'environnement de la CI : préférez les identités fédérées (OIDC) auprès des fournisseurs cloud.
- Activer la double authentification sur les comptes de publication npm et PyPI de votre équipe.
5. Surveiller après coup
Un paquet peut être reconnu comme malveillant des jours après son installation. Un inventaire à jour (SBOM) confronté régulièrement au flux OpenSSF vous prévient si un composant déjà en place est requalifié.
Si vous êtes touché
- Considérez la machine ou le runner CI comme compromis.
- Révoquez et renouvelez tous les secrets accessibles depuis cet environnement : jetons npm et GitHub, clés cloud, clés SSH.
- Supprimez la version piégée, fixez une version saine dans le lockfile, reconstruisez depuis un environnement propre.
- Vérifiez les journaux d'accès de vos comptes cloud et de vos dépôts sur la période concernée.
- Selon votre secteur, évaluez vos obligations de notification (NIS2, RGPD si des données personnelles sont en jeu).
Questions fréquentes
Comment savoir si un paquet npm est malveillant ?
Aucun signe visuel n'est fiable à lui seul. Les indices : paquet très récent, nom proche d'un paquet connu, peu de téléchargements, script d'installation qui télécharge ou exécute du code. La vérification sérieuse consiste à confronter automatiquement vos dépendances aux bases de paquets malveillants comme le flux OpenSSF publié dans OSV.
Les paquets malveillants ont-ils un numéro CVE ?
Rarement. Ils sont signalés dans des bases dédiées, notamment le flux OpenSSF (identifiants MAL-) diffusé par OSV. Un outil de sécurité qui ne consulte que les CVE ne les détecte pas.
Dependabot protège-t-il des paquets malveillants ?
Dependabot ouvre des pull requests de mise à jour, ce qui peut au contraire introduire une version récente piégée si personne ne vérifie. GitHub a ajouté des alertes sur certains paquets malveillants, mais la protection la plus efficace reste une règle d'âge minimum et une vérification bloquante sur chaque PR. Voir Dependabot suffit-il ?.