Menaces

npm, PyPI, Docker Hub : pourquoi la supply chain open source est devenue une cible majeure

  • Publié le
  • 16 min de lecture
  • 12 sources citées

Le 19 mars 2026, un attaquant disposant d'accès obtenus antérieurement a publié une version piégée du scanner de vulnérabilités Trivy, réécrit 76 des 77 étiquettes de version de l'action GitHub associée et remplacé les sept étiquettes d'une seconde action. Le code injecté extrayait des secrets de la mémoire du processus d'exécution et de plus de cinquante emplacements du système de fichiers, avant de lancer le scan légitime pour ne rien laisser paraître.

Cinq jours plus tard, des identifiants récupérés lors de cette compromission ont servi à publier des versions malveillantes de paquets Python largement utilisés. PyPI a documenté des fenêtres d'exposition de deux heures et demie à moins de quatre heures, pendant lesquelles les versions piégées de l'un de ces paquets ont été téléchargées environ 119 000 fois.

Ces chiffres résument la question. Les registres de paquets et d'images sont devenus des cibles parce qu'ils offrent un rapport inégalé entre l'effort d'intrusion et la portée obtenue : un compte, une étiquette de version, une image de base, et le code s'exécute dans des milliers de chaînes de construction qui l'ont demandé elles-mêmes.

Colis aux couleurs de npm, PyPI et Docker Hub sur un convoyeur, dont l'un est marqué comme malveillant

Faits, analyse et incertitudes

Faits confirmés

  • Aqua Security a publié le bulletin GHSA-69fq-xp46-6x23, suivi sous l'identifiant CVE-2026-33634, décrivant la compromission temporaire de l'écosystème Trivy.
  • Le 19 mars 2026, une activité malveillante a été détectée à 17 h 43 UTC ; la version piégée v0.69.4 du binaire a été publiquement disponible à partir de 18 h 22 UTC et retirée environ trois heures plus tard.
  • 76 des 77 étiquettes de version du dépôt trivy-action et les sept étiquettes du dépôt setup-trivy ont été remplacées par du contenu malveillant, avec des fenêtres d'exposition de l'ordre de quatre à douze heures.
  • Les 22 et 23 mars 2026, deux images supplémentaires ont été publiées sur Docker Hub et retirées après une dizaine d'heures.
  • Le code injecté extrayait des secrets depuis la mémoire du processus d'exécution et depuis plus de cinquante emplacements du système de fichiers : clés SSH, identifiants AWS, GCP et Azure, jetons Kubernetes, configurations Docker, fichiers d'environnement et identifiants de bases de données, puis les chiffrait avant exfiltration.
  • Microsoft a publié le 24 mars 2026 un guide de détection, d'investigation et de défense, et recommande d'épingler les GitHub Actions sur une empreinte de commit plutôt que sur une étiquette de version, ces étiquettes pouvant être réécrites par un attaquant.
  • PyPI a publié le 2 avril 2026 un rapport d'incident sur les attaques visant litellm et telnyx, consécutives à l'exposition d'un jeton d'API lors de la compromission de Trivy.
  • PyPI documente une fenêtre d'exposition totale de 2 h 32 pour le premier paquet et de 3 h 42 pour le second, et indique qu'environ 119 000 téléchargements des versions compromises ont eu lieu pendant cette période.
  • PyPI indique avoir reçu treize signalements via sa fonction de signalement de code malveillant, et avoir déclenché une mise en quarantaine automatisée grâce au poids accordé aux rapporteurs de confiance.
  • PyPI recommande aux consommateurs l'usage de fichiers de verrouillage comportant des empreintes et l'adoption d'un délai de refroidissement avant l'installation de versions récemment publiées, et aux mainteneurs l'usage de la publication de confiance plutôt que de jetons de longue durée, ainsi que l'authentification à deux facteurs par clé matérielle.
  • GitHub a révoqué définitivement l'ensemble des jetons npm historiques le 9 décembre 2025, introduit des sessions de courte durée à la connexion et plafonné à 90 jours la durée de vie des jetons en écriture créés ensuite.
  • PyPI indique avoir traité plus de 2 000 signalements de code malveillant sur l'année 2025, dont 66 % en moins de quatre heures, et compter plus de 50 000 projets utilisant la publication de confiance.

Notre analyse

  • La séquence Trivy puis PyPI est l'élément le plus instructif de l'année : un outil de sécurité compromis devient le moyen d'obtenir les identifiants qui serviront à compromettre un autre écosystème. La chaîne d'approvisionnement n'est pas linéaire, elle est maillée.
  • Le choix de réécrire des étiquettes de version plutôt que de publier une nouvelle version est délibéré : il atteint rétroactivement tous les utilisateurs qui se croyaient figés sur une version connue.
  • Les 119 000 téléchargements en deux heures et demie donnent la mesure du problème : aucune organisation ne peut réagir dans ce délai. La protection ne peut donc pas être une réaction, elle doit être une propriété de la chaîne de construction.

Ce qui reste incertain

  • L'attribution de ces campagnes n'est établie par aucune source institutionnelle que nous ayons pu consulter.
  • Le nombre d'organisations françaises réellement touchées n'est documenté nulle part.
  • Les estimations globales du nombre de paquets malveillants publiées par différents éditeurs reposent sur des méthodologies distinctes et ne sont pas comparables entre elles. Nous ne les additionnons pas.

Pourquoi les registres sont devenus une cible de premier plan

Une application contemporaine est composée à plus de quatre-vingts pour cent de code qu'elle n'a pas écrit. Ce code provient de registres publics, est récupéré automatiquement lors de chaque construction, et s'exécute avec les droits de la chaîne d'intégration continue. Pour un attaquant, c'est une configuration remarquable : le code n'a pas à franchir de périmètre, il est téléchargé volontairement.

  • La cible n'est pas l'organisation visée mais un mainteneur, souvent bénévole, dont les moyens de protection sont sans rapport avec ceux d'une entreprise
  • La portée est démultipliée : un paquet largement utilisé donne accès à tous ceux qui l'installent, y compris à des organisations qui ignorent en dépendre
  • L'exécution est privilégiée : les scripts d'installation et les étapes de construction s'exécutent avec les secrets du pipeline
  • La détection est difficile : un paquet malveillant fait aussi ce qu'il est censé faire, et le comportement anormal se noie dans une construction qui réussit
  • La fenêtre nécessaire est courte : quelques heures suffisent à atteindre des dizaines de milliers d'environnements
  • Le butin est directement réutilisable : les secrets collectés donnent accès à d'autres registres, d'autres dépôts, d'autres environnements cloud

Les voies d'entrée documentées

  • Compte de mainteneur compromis

    Hameçonnage ciblé, jeton exposé dans un journal de construction, réutilisation de mot de passe. C'est la voie la plus productive, parce qu'elle permet de publier sous une identité légitime, avec la réputation du projet.

  • Étiquettes de version réécrites

    Une étiquette Git n'est pas immuable. Un attaquant qui dispose d'un accès en écriture peut la faire pointer ailleurs. Les utilisateurs qui référencent une version par son étiquette récupèrent alors un autre contenu sans rien changer chez eux.

  • Typosquatting

    Publication d'un paquet au nom proche d'un paquet légitime, misant sur une faute de frappe ou une confusion de nom. Coût nul pour l'attaquant, efficacité faible mais non nulle, et durée de vie limitée par la modération des registres.

  • Confusion de dépendances

    Publication, sur un registre public, d'un paquet portant le nom d'un paquet interne à une organisation. Si l'outil de construction interroge le registre public avant le registre privé, ou privilégie la version la plus élevée, il installe celui de l'attaquant.

  • Compromission d'une dépendance légitime

    Le cas le plus difficile à détecter : le paquet attendu, publié par le projet attendu, contenant en plus du code malveillant. C'est ce qui s'est produit avec Trivy, puis avec les paquets Python atteints ensuite.

  • Images de conteneurs publiques

    Les images publiques sont récupérées automatiquement par les chaînes de construction et les orchestrateurs. Unit 42 a documenté des campagnes d'images de minage publiées sur un registre public et téléchargées à très grande échelle avant leur retrait.

Ces six voies ne sont pas concurrentes : elles s'enchaînent. La compromission d'un compte de mainteneur permet la réécriture d'étiquettes, qui permet la collecte de secrets, qui permet la compromission d'autres comptes dans un autre écosystème. C'est ce mécanisme de propagation, et non la sophistication technique d'un paquet particulier, qui fait la gravité du phénomène.

Ce que cherche un paquet malveillant

Le code injecté dans l'écosystème Trivy donne une image précise des objectifs. Il ne cherchait ni à chiffrer des données ni à saboter des constructions : il cherchait des identifiants, méthodiquement, dans la mémoire du processus d'exécution et dans plus de cinquante emplacements du système de fichiers.

  • Clés SSH privées, qui ouvrent des accès à des serveurs et à des dépôts
  • Identifiants d'accès aux fournisseurs cloud, qui ouvrent des environnements entiers
  • Jetons Kubernetes, qui donnent la main sur des charges de travail en production
  • Configurations de registres d'images, qui permettent de publier à son tour
  • Fichiers d'environnement et identifiants de bases de données
  • Secrets du pipeline d'intégration continue, présents en mémoire au moment même de l'exécution

Un détail mérite d'être relevé : après la collecte, le code lançait le scan légitime. La construction réussissait, les rapports étaient produits, rien n'était visible. C'est la signature d'une opération pensée pour durer, et non pour un gain immédiat.

Les mesures qui réduisent réellement l'exposition

Aucune mesure ne supprime le risque d'utiliser du code écrit par d'autres. En revanche, plusieurs pratiques transforment une compromission d'écosystème en incident circonscrit. Elles ont un point commun : elles rendent la chaîne de construction reproductible, donc vérifiable.

Figer ce qui est installé

Reproductibilité de la construction

  • Fichiers de verrouillage comportant des empreintes cryptographiques, et non de simples numéros de version
  • Épinglage des actions et des étapes de construction sur une empreinte de commit plutôt que sur une étiquette de version
  • Images de conteneurs référencées par leur empreinte, pas par une étiquette mutable
  • Délai de refroidissement avant adoption d'une version récemment publiée, de l'ordre de quelques jours
  • Miroir interne des dépendances, alimenté et contrôlé par l'organisation
  • Priorité explicite du registre privé sur le registre public, pour fermer la confusion de dépendances

Le délai de refroidissement mérite une mention particulière. Les fenêtres documentées par PyPI sont de deux à quatre heures entre publication et mise en quarantaine. Un délai d'adoption de trois jours aurait suffi, dans ces deux cas, à ne jamais installer les versions piégées. C'est une mesure simple, gratuite et efficace, qui coûte seulement une part de réactivité sur les mises à jour.

Supprimer les secrets de longue durée

Les deux grands registres ont fait converger leurs orientations. npm a révoqué en décembre 2025 l'ensemble de ses jetons historiques, introduit des sessions courtes et plafonné la durée de vie des jetons en écriture. PyPI généralise la publication de confiance, qui remplace un jeton stocké par une identité vérifiée auprès du fournisseur d'intégration continue, et génère automatiquement une attestation de provenance.

Pour une organisation, la transposition est directe : aucun secret de publication ne devrait être stocké de façon permanente dans une variable de pipeline. Ce qui ne peut pas être volé n'a pas besoin d'être surveillé.

Savoir ce que l'on utilise

  • Inventaire des composants

    Une nomenclature logicielle, ou SBOM, répond à une question que beaucoup d'organisations ne peuvent pas trancher en quelques heures : est-ce que ce paquet compromis est présent quelque part chez moi, et dans quelles versions ?

  • Provenance et signature

    Les attestations de provenance permettent de vérifier qu'un artefact a bien été produit par la chaîne de construction annoncée. Le référentiel SLSA formalise des niveaux de garantie progressifs sur ce point.

  • Veille sur les paquets malveillants

    Le dépôt public de l'OpenSSF rassemble les signalements de paquets malveillants au format Open Source Vulnerability, ce qui permet de les intégrer aux outils existants plutôt que de suivre des annonces éparses.

  • Analyse automatisée

    Les outils de mise à jour automatique et de recherche de vulnérabilités dans les dépendances restent utiles, à condition de ne pas les configurer pour appliquer sans délai la dernière version publiée.

  • Moindre privilège dans la chaîne de construction

    Permissions minimales par tâche, séparation des environnements, interdiction pour une tâche de construction d'accéder à des secrets de production. La collecte décrite plus haut ne récupère que ce qui est accessible.

  • Authentification forte des mainteneurs

    Pour les organisations qui publient elles-mêmes des paquets : authentification à deux facteurs par clé matérielle sur tous les comptes de publication, sans exception ni procédure de secours affaiblie.

Questions fréquentes

Qu'est-ce qu'une attaque sur la chaîne d'approvisionnement logicielle ?

Une attaque qui vise un maillon en amont — un paquet, une image, une action de construction — afin d'atteindre toutes les organisations qui l'utilisent. Le code malveillant n'a pas à franchir de périmètre : il est téléchargé et exécuté volontairement par les chaînes de construction de ses victimes.

Pourquoi épingler sur une empreinte de commit plutôt que sur une version ?

Parce qu'une étiquette de version peut être réécrite par quiconque dispose d'un accès en écriture au dépôt. Lors de la compromission de mars 2026, 76 des 77 étiquettes d'une action GitHub ont été redirigées vers du code malveillant. Une empreinte de commit, elle, désigne un contenu et ne peut pas être détournée.

Un fichier de verrouillage suffit-il à me protéger ?

Il protège contre l'installation involontaire d'une nouvelle version, ce qui est déjà considérable, à condition qu'il contienne des empreintes et pas seulement des numéros de version. Il ne protège pas si vous mettez à jour ce fichier pendant la fenêtre de compromission, d'où l'intérêt d'un délai de refroidissement.

Que faire si une dépendance que j'utilise a été compromise ?

Identifier les constructions qui l'ont installée pendant la fenêtre concernée, revenir à une version sûre, puis faire tourner tous les secrets qui étaient accessibles à ces constructions : jetons de registre, identifiants cloud, clés SSH, secrets de pipeline. L'absence de preuve d'exfiltration ne dispense pas de la rotation.

Les registres publics font-ils quelque chose ?

Oui, et les mesures sont substantielles. npm a révoqué ses jetons historiques et limité la durée de vie des nouveaux. PyPI a traité plus de 2 000 signalements de code malveillant en 2025, dont deux tiers en moins de quatre heures, et développe la publication de confiance et les attestations de provenance. Ces mesures réduisent la fenêtre d'exposition sans l'annuler.

Faut-il renoncer aux dépendances open source ?

La question ne se pose pas en ces termes : le code propriétaire consomme les mêmes bibliothèques, sans toujours le dire. Le sujet est de savoir ce que l'on installe, depuis quelle source, dans quelle version exacte, et avec quels droits d'exécution.

Sources