Dépôt Zod compromis : vérifiez la publication sur npm
Le dépôt Zod a contenu du code malveillant, mais aucun paquet Zod infecté n'a été publié sur npm. Quatre vérifications pour établir ce qui a été exposé.
Ernest Bursa
Aucun paquet Zod 4.6.6 malveillant n’a été publié sur npm. Le 21 septembre 2026, des commits malveillants ont été ajoutés au dépôt GitHub de Zod, mais le processus de publication n’a pas été lancé pour ces changements. Standard Schema n’est pas non plus parvenu à l’étape de publication. Une version proposée de @nubjs/[email protected] est entrée dans le processus de validation de npm, qui l’a bloquée avant qu’elle soit accessible au public. Un même incident a donc eu trois issues différentes, selon le compte rendu de l’incident publié par npm et GitHub et la mise au point de Colin McDonnell, mainteneur de Zod.
Si votre dépôt est compromis, la question urgente ne se limite pas à la présence de code malveillant sur GitHub. Déterminez jusqu’où ce code est allé : historique du dépôt, autorisation de publication, validation par le registre et contenu du paquet, puis utilisation en aval. Chaque étape demande ses propres preuves et sa propre réponse.
Qu’est-il arrivé à Zod, Standard Schema et Nub ?
Le 21 septembre, des modifications malveillantes liées entre elles sont apparues dans les dépôts publics de Zod, Standard Schema et Nub. Les équipes qui ont enquêté sur l’incident ont identifié les commits concernés et décrit un code conçu pour récupérer puis exécuter du JavaScript supplémentaire pendant l’installation, à condition qu’il ait été intégré à un paquet et qu’un utilisateur installe celui-ci. Les éléments publiés ne démontrent pas que ce code a été exécuté sur la machine d’un utilisateur en aval. Les métadonnées des commits ne révèlent pas non plus comment l’attaquant a obtenu l’accès.
Les résultats de publication comptent davantage qu’un titre commun aux trois projets :
| Projet | Jusqu’où la modification malveillante est allée | Résultat sur npm |
|---|---|---|
zod |
Commit dans le dépôt public | Aucune tentative de publication sur npm ; aucune version malveillante de Zod accessible à l’installation |
standard-schema |
Commit dans le dépôt public | Aucune tentative de publication sur npm ; aucune version malveillante de Standard Schema accessible à l’installation |
@nubjs/[email protected] |
Processus de publication de npm | Version retenue pendant la validation, puis bloquée avant d’être accessible au public |
Ce tableau reprend les informations de publication recueillies par l’équipe chargée de l’incident. La seule page d’un commit GitHub ne permet pas de les établir. Il dissipe aussi une ambiguïté facile à manquer : Nub est entré dans le processus de npm, sans devenir un paquet public installable. Soumettre une version ne signifie pas qu’un utilisateur pouvait normalement la télécharger.
Les équipes d’intervention ont présenté les trois dépôts ensemble, mais McDonnell a contesté une formulation pouvant laisser croire que l’analyse de npm avait arrêté Zod. Selon son témoignage dans la même discussion, les modifications malveillantes n’ont pas déclenché le processus de publication de Zod. Standard Schema n’a pas non plus été publié. L’analyse de npm a détecté la tentative concernant Nub. Le tableau détaillé de l’incident et la rectification du mainteneur concordent sur ces résultats ; leur désaccord porte sur l’interprétation que suggère la présentation générale.
Pourquoi la compromission du dépôt Zod n’a-t-elle pas atteint npm ?
Un push Git modifie l’état d’un dépôt. Il ne donne pas, à lui seul, le droit de publier sur npm. D’après le mainteneur, Zod utilisait un environnement de déploiement GitHub dédié et la publication de confiance de npm pour ses tâches de publication ; un simple commit ou tag ne pouvait pas déclencher cette tâche. Il a évoqué la compromission probable d’un identifiant permettant de pousser du code, tout en précisant que le point d’entrée exact restait à établir. Il s’agit d’une hypothèse, pas d’une conclusion. Son témoignage établit le fait plus limité qui importe ici : les commits malveillants n’ont pas lancé le processus de publication de Zod.
La publication de confiance s’appuie sur une identité d’intégration continue configurée et sur OIDC pour autoriser la publication sans fournir à ce processus un jeton npm permanent. Elle répond à la question « qui, ou quel système, peut demander une publication ? », pas à celle de l’innocuité du code. Les environnements GitHub peuvent ajouter des restrictions par branche et exiger une approbation avant qu’une tâche ne s’exécute ou n’accède aux secrets de l’environnement. Votre protection dépend des déclencheurs, autorisations, réglages de l’environnement et autres voies de publication réels de votre dépôt. Si le processus lui-même est compromis, ou si un autre acteur autorisé publie, l’analyse change.
Nub illustre l’étape suivante. Selon le mainteneur, la création d’un tag pouvait déclencher son processus de publication. La version proposée 0.9.4 est arrivée chez npm, où la validation préalable l’a signalée et retenue. La description de l’analyse avant publication de npm distingue le dépôt d’un paquet de sa mise à disposition pour installation. L’analyse a arrêté cette tentative concernant Nub. Elle n’a pas arrêté Zod ni Standard Schema, puisque aucun des deux n’était entré dans ce processus.
Aucune de ces protections ne permet d’exclure une dépendance Git directe, une archive source téléchargée ou du code exécuté depuis un ancien état compromis du dépôt. Le compte rendu de l’incident ne fait état d’aucune exécution prouvée par ces voies, ni d’un nombre confirmé d’installations touchées.
Pourquoi les notes de publication de Zod 4.6.6 ont-elles suscité l’alerte ?
Le 12 octobre, une discussion sur Hacker News demandant si Zod 4.6.6 était compromis a pointé vers un commit malveillant de septembre visible dans la liste de commits générée automatiquement sur la page GitHub de la version v4.6.6. Cette piste méritait une enquête. Elle ne prouvait pas que le code malveillant figurait dans l’archive publiée sur npm.
La modification malveillante avait été annulée, mais son commit restait dans la période couverte par les notes de publication. McDonnell a expliqué que le code était absent du paquet publié. C’est là qu’une question sur l’historique du dépôt peut devenir, à tort, un verdict sur le contenu du paquet. Un tag peut contenir un commit d’annulation ; une page de publication peut afficher aussi bien l’ajout malveillant que sa suppression. Vérifiez le résultat de la compilation et ce que le registre a rendu accessible avant d’affirmer qu’une installation était infectée.
Une autre mesure a été prise le 12 octobre, distincte de la réponse du 21 septembre. McDonnell a déclaré avoir retiré les commits malveillants de l’historique après avoir mis en balance la transparence et le risque d’exécuter ce code en récupérant un ancien état, par exemple avec git bisect. Il a également indiqué que ce nettoyage avait fait perdre à v4.6.6 son attestation de provenance npm et qu’une version v4.6.7 avait suivi. Sa mise à jour décrit une conséquence ultérieure de la modification de l’historique. La perte de provenance ne prouve pas que le paquet 4.6.6 précédent contenait un logiciel malveillant.
La provenance a une fonction précise. La documentation de npm décrit des attestations qui relient un paquet publié à son dépôt source et au processus qui l’a produit. Ce lien aide à déterminer comment l’archive a été créée. Il ne s’agit pas d’une analyse de logiciels malveillants, et un résumé de publication généré par GitHub ne remplace pas l’examen du paquet.
Quelles sont les quatre vérifications à faire côté maintenance ?
Appliquez les mêmes quatre vérifications à toute suspicion de compromission entre dépôt et paquet. Partez du fait observé, conservez les preuves et ne passez à l’étape suivante que si elle dispose de ses propres éléments. Cette méthode pratique découle de l’incident Zod et des mécanismes de publication documentés par npm et GitHub. Elle ne prétend pas que chaque étape ci-dessous s’est produite en septembre.
1. Établissez ce qui a changé dans le dépôt
Consignez les identifiants des commits suspects, les fichiers touchés, les dates et heures de création et d’envoi, les branches, les tags et le moment où la modification a été retirée. Conservez le diff d’origine et les journaux avant de nettoyer l’historique. Examinez séparément les manifestes des paquets, les scripts d’installation, les scripts de compilation et les fichiers qui définissent les processus automatisés. Une modification inactive dans le dépôt peut devenir active lors de la compilation ou de l’installation ; un commit inquiétant peut aussi avoir été annulé avant toute compilation.
Rédigez une phrase qui distingue le constat de son explication : « Le commit X a ajouté du code au fichier Y et a été envoyé à l’heure Z » décrit une observation. « Une clé SSH volée en est la cause » exige des preuves sur les accès ou les identifiants. Le témoignage publié par McDonnell n’établissait pas de point d’entrée définitif : ne l’inventez pas dans une communication sur l’incident. Le compte rendu renvoie aux modifications publiques sans démontrer comment l’identifiant initial a été compromis.
Cette première vérification établit où le code malveillant était présent, y compris dans les anciens états du dépôt, et non si une publication a eu lieu. Préservez ces preuves si vous réécrivez ensuite l’historique public.
2. Déterminez si la tâche de publication pouvait s’exécuter et si elle s’est exécutée
Lisez la configuration du processus au lieu de tirer des conclusions d’un tag. Quel événement déclenche le processus de publication : un push, un tag ou un lancement manuel ? Une fois le processus déclenché, une approbation de l’environnement est-elle requise avant que la tâche ne s’exécute ? Quelles branches et quels formats de tag sont autorisés ? Qui peut modifier le processus et les règles de l’environnement ? npm n’accepte-t-il que le publieur OIDC prévu, ou des identifiants de publication directe et un autre processus restent-ils autorisés ?
Consultez ensuite le journal d’exécution pour la période concernée. Notez l’identifiant de l’exécution, la version du fichier de configuration, la référence qui l’a déclenchée, l’acteur, l’approbation de l’environnement et le résultat de la publication. « Le processus dispose d’un déclencheur manuel » et « aucune exécution concernée n’a eu lieu » sont deux affirmations différentes. Une capture de configuration prise après la correction ne prouve pas quelle règle s’appliquait lors de la compromission ; conservez la configuration historique et les traces d’audit correspondantes.
Dans cet incident, le mainteneur affirme que le processus de publication de Zod ne s’est pas exécuté pour les commits malveillants. Cette information est plus solide que l’hypothèse selon laquelle npm les aurait détectés. La publication de confiance et les environnements de déploiement décrivent les protections générales ; son témoignage donne le résultat propre au projet.
3. Établissez l’état du registre et examinez le paquet
Distinguez quatre états : une publication a été tentée ; une version est entrée en validation ; elle a été retenue ou bloquée ; ou elle est devenue publiquement installable. Pour toute version publique, relevez le nom exact du paquet, la version, l’heure de publication, l’URL et l’empreinte de l’archive, ainsi que les fichiers qu’elle contient. Comparez cette archive avec le code suspect et avec le résultat de la compilation. Un numéro de version npm ne dit pas, à lui seul, quels octets les utilisateurs ont reçus.
Le personnel du registre peut disposer de journaux de validation privés. Indiquez la source de preuve qui fonde chaque conclusion. Le compte rendu de l’incident fait état de la validation puis du blocage de Nub avant sa mise à disposition, et d’aucune tentative de publication des commits malveillants de Zod ou de Standard Schema. La seule page de publication ne permettait pas de trancher.
Si votre paquet dispose d’une attestation de provenance, utilisez-la pour relier l’archive au code source et au processus qui l’a produite. Si elle manque, dites-le et cherchez pourquoi. Un badge absent n’est pas un verdict de malveillance ; un badge présent ne prouve pas non plus que le code est sain. Le guide de npm sur la provenance précise ce que l’attestation relie.
4. Déterminez qui a pu utiliser le code
Une fois établi si une archive malveillante était installable publiquement, cherchez des preuves en aval. Vérifiez dans les fichiers de verrouillage des dépendances, les journaux d’installation, les caches, les manifestes de déploiement et les traces de compilation la version et l’empreinte exactes. Examinez séparément les URL Git, les téléchargements directs du code source, les archives locales et les anciens états du dépôt. Le blocage par le registre limite l’exposition via ce registre ; il ne dit pas si quelqu’un a obtenu le même code autrement.
Distinguez mise à disposition, téléchargement et exécution. Un paquet public peut n’apparaître dans aucune de vos compilations. Un fichier de verrouillage peut mentionner une version sans prouver qu’un script d’installation a été exécuté dans un environnement donné. Une archive source peut avoir été téléchargée sans être exécutée. Quand les preuves s’arrêtent à une étape, votre communication doit s’y arrêter aussi.
Conservez les journaux avant que la rotation des jetons, la suppression des caches ou le nettoyage du dépôt n’effacent la période à examiner. Révoquez ou renouvelez rapidement les identifiants lorsque les faits le justifient, puis vérifiez que les anciens ne fonctionnent plus. Notre liste de vérification pour clore un signalement d’identifiant divulgué distingue la suppression de l’exposition, la révocation et l’enquête. Elle ne remplace pas les vérifications du processus de publication ci-dessus.
Comment communiquer le résultat et renforcer la publication ?
Publiez un compte rendu bref et précis pour chaque étape. Nommez les dépôts modifiés, les processus qui se sont exécutés ou non, les versions entrées en validation et les archives devenues installables. Indiquez la source de chaque affirmation et les questions encore ouvertes. Un mainteneur peut dire « nous avons trouvé du code malveillant dans l’historique, mais aucun paquet npm malveillant n’a été publié » sans minimiser la compromission du dépôt. Si une archive malveillante est devenue publique, l’équipe doit nommer les versions et les utilisateurs concernés, au lieu de s’en tenir à « le dépôt a été compromis ».
Respectez la chronologie. Le 21 septembre correspond à la compromission des dépôts et à la tentative de publication de Nub bloquée par npm. Dans une modification datée du 24 septembre, McDonnell indique que ses paquets ont ensuite adopté une publication par étapes, limitée à un environnement et déclenchée manuellement. Il s’agit d’une mesure prise après l’incident, pas de la protection qui avait déjà arrêté Zod. Selon la documentation de npm sur cette méthode, le dépôt d’une version en attente ne demande pas de double authentification ; son approbation avant mise à disposition l’exige. Une configuration de publication de confiance limitée à cette étape peut refuser la publication directe, mais les indications de npm autorisent aussi plusieurs publieurs. Vérifiez qu’aucune voie directe imprévue ne reste ouverte.
Lorsque plusieurs projets sont concernés par un même signalement, coordonnez la communication externe sans confondre leurs situations. Un incident limité au dépôt, une soumission bloquée et un paquet malveillant public n’appellent pas les mêmes destinataires ni les mêmes mots. Notre guide de divulgation coordonnée entre plusieurs fournisseurs traite séparément du partage des responsabilités et des délais.
Kit peut recevoir le signalement d’un chercheur par un programme public de divulgation des vulnérabilités, lui attribuer un responsable, suivre l’accusé de réception et la correction, puis conserver une trace de la divulgation. Son espace CSIRT peut contenir des liens vers un correctif ou un ticket externe. L’équipe technique doit toujours examiner elle-même l’historique Git, les autorisations de publication, l’état de npm et les octets du paquet. Kit n’analyse pas les paquets npm et ne certifie pas qu’une version est saine.
La leçon pratique de l’incident Zod est précise et largement applicable : déterminez jusqu’où le code est allé avant de définir l’étendue des conséquences. Réunissez sur une page les preuves relatives au dépôt, au processus de publication, au registre et au paquet. Expliquez ensuite aux utilisateurs ce qui a été exposé, ce qui a été arrêté et ce qui reste inconnu. Pour faciliter le prochain signalement, commencez par notre guide de mise en place d’un programme de divulgation des vulnérabilités.
Articles similaires
Essayez Kit pendant 30 jours.
Le recrutement, les rapports de sécurité et la formation dans un seul compte, pour les équipes où rien de tout cela n'est un poste à plein temps. 30 jours d'essai gratuit, carte bancaire demandée. Résiliez avant la fin et vous ne payez rien.
Essayez gratuitement