Principaux enseignements
- Go identifie un paquet en fonction de son emplacement plutôt qu'en fonction d'un nom appartenant à quelqu'un ; ainsi, un nom d'utilisateur GitHub qui n'est plus valide peut, à lui seul, devenir un problème de chaîne d'approvisionnement.
- La base de données de sommes de contrôle garantit que tout le monde obtient le même code pour une version donnée, mais pas que cette version provienne d'une personne de confiance.
- GitHub supprime certains espaces de noms populaires, mais les téléchargements effectués via le miroir de modules de Go ne sont pas considérés comme des clones déclenchant cette protection.
- Les chemins qui doivent faire l'objet d'un audit sont les petits chemins transitifs que personne ne lit.
En décembre 2023, des chercheurs de VulnCheck ont recherché sur GitHub des dépôts Go se trouvant dans un état permettant leur récupération, et le nombre total s'est avéré bien plus élevé que ce que la plupart des gens auraient pu imaginer. Plus de 15 000. Plus de 9 000 ont été exposés à la suite d’un changement de nom d’utilisateur sur GitHub, et plus de 6 000 autres à la suite de la suppression de comptes. Au total, ces dépôts contiennent plus de 800 000 versions de modules Go.
Tout cela ne nécessite ni identifiants volés, ni pipeline de compilation compromis. Il suffit simplement qu'un compte expire et que quelqu'un s'en aperçoive avant le propriétaire initial.
Ces chiffres datent désormais de quelques années, et personne n’en a publié de nouveaux depuis. Le mécanisme sous-jacent n’a toutefois pas changé, et la raison pour laquelle cela fonctionne en Go et pratiquement nulle part ailleurs tient à la manière dont Go définit ce qu’est un paquet.
Pourquoi l'identité d'un paquet « go » correspond à un emplacement plutôt qu'à un nom
La plupart des registres importants tiennent un registre des droits de propriété. npm sait qui est autorisé à publier axios. PyPI sait qui peut publier une nouvelle version de requests. Maven Central vérifie un espace de noms avant que quiconque ne puisse revendiquer un groupId sous celui-ci.
Dans Go, un chemin d'accès fait également office d'adresse.
« github.com/someuser/somelib » n’est pas un nom enregistré auprès d’un registre Go. Il s’agit d’un chemin d’accès au module qui indique à la chaîne d’outils où chercher, et celui qui contrôle cet emplacement contrôle les versions qui pourront y être mises à disposition par la suite. Lorsque le compte associé disparaît et que quelqu’un d’autre revendique ce nom d’utilisateur, le chemin d’importation dans votre fichier go.mod pointe désormais vers son code.
Il s'agit là d'un phénomène bien différent des campagnes de piratage de comptes qui font la une ces derniers temps, comme PolinRider. Cette campagne a également touché des modules Go en 2026, mais le mécanisme n’est pas le même. Ces attaquants avaient pris le contrôle de comptes encore actifs et, dans plusieurs cas, avaient réécrit des balises Git pour dissimuler leurs agissements. Le « repojacking » est plus discret, et à certains égards plus simple, car il ne nécessite aucune intrusion. Une fois qu’un compte a disparu, il n’y a plus rien à défendre.
Le système de résolution des modules de Go est élégant, et cela mérite d’être souligné avant d’aborder ses défauts. La commande « go get github.com/user/lib » utilise par défaut le proxy de modules pour résoudre l’adresse, enregistre une version et génère un hachage. Pas de compte, pas d’envoi au registre, pas de pipeline de publication. Il suffit de pousser une balise de version correctement nommée pour que la version existe, sans étape de publication distincte entre les deux.
Cela fonctionne parce que le chemin d'importation fait office de référence absolue. Ce chemin indique à la chaîne d'outils où chercher, et aucun autre système n'enregistre qui est autorisé à y placer du code.
Comparez les informations dont dispose réellement chaque registre concernant un paquet.
| Registre | L'identité, c'est | Registre des propriétaires | Récupérable après abandon |
| npm | Un nom enregistré | Oui, associé à un compte | Non, les noms restent réservés |
| PyPI | Un nom enregistré | Oui, associé à un compte | Ce n'est que par le biais d'une procédure officielle |
| Maven Central | Un espace de noms associé à un domaine vérifié ou à un référentiel source | Oui, espace de noms vérifié | Oui, si le nom de domaine n'est plus valide |
| crates.io | Un nom enregistré | Oui, associé à un compte | Non, les noms restent réservés |
| Packagist | Un nom enregistré | Oui, associé à un compte | Non, les noms restent réservés |
| Modules Go | Un site VCS | Aucun | Oui, dès que l'emplacement se libère |
Maven est confronté à sa propre version de ce problème avec domaines expirés, ce que l'étude « MavenGate » avait décrit en janvier 2024. Les identifiants de groupe (Group ID) sont dérivés des domaines ; ainsi, lorsqu'un domaine expire, l'espace de noms qui lui est associé est perdu.
Packagist a également connu un cas similaire. Lors d'un incident survenu en 2022, un chercheur a piraté le dépôt GitHub associé à un paquet Packagist et a réussi à y publier un logiciel malveillant, car Packagist parcourait GitHub à la recherche de nouvelles versions sans étape de publication distincte. Cette faille a depuis été corrigée, et après l’ incident de réécriture des balises Laravel-Lang en mai 2026, Packagist est allé plus loin et a a rendu les versions stables immuables, une mesure annoncée en mai et mise en œuvre en juillet. Il convient toutefois de préciser clairement ce que cela corrige. Les versions immuables empêchent quiconque de déplacer la référence Git d’une version publiée. Elles ne font rien contre le fait que quelqu’un s’approprie un espace de noms abandonné et publie quelque chose de nouveau sous celui-ci.
Pour Go, ce deuxième scénario correspond à la configuration par défaut de tout module hébergé sur un compte GitHub personnel. L’équipe de sécurité de GitHub a désigné Go comme l’un des trois moyens permettant aux builds de récupérer du code directement depuis un dépôt dans son article de 2024 sur le « repojacking », aux côtés de GitHub Actions et des sous-modules Git. Pour ces deux derniers, elle recommande de se verrouiller sur un commit spécifique. Go dispose d’une couche d’intégrité dont ils sont dépourvus, puisque les versions des modules sont authentifiées par rapport à go.sum et, par défaut, par rapport à la base de données publique de sommes de contrôle. C’est là que les choses deviennent plus intéressantes qu’il n’y paraît à première vue.
Il existe également une forme plus insidieuse de ce risque. Une grande partie des composants open source intégrés au code de production n'ont pas fait l'objet d'une mise à jour depuis des années, et ce sont précisément les projets en sommeil dont les responsables finissent par supprimer leur compte ou laisser expirer leur nom de domaine. Dans la plupart des écosystèmes, cela pose un problème de correction des failles. Dans Go, cela constitue également une porte d'entrée pour les attaques par prise de contrôle.
Comment fonctionne le « repojacking » sur un chemin d'importation
Deux événements au niveau du compte libèrent un chemin d'accès GitHub. La suppression d'un compte libère le nom d'utilisateur, et la modification d'un nom d'utilisateur libère l'ancien. Dans les deux cas, github.com/olduser/lib reste disponible, et la prochaine personne à enregistrer ce nom d'utilisateur pourra recréer un dépôt portant ce nom et en devenir propriétaire. La suppression d'un seul dépôt au sein d'un compte qui existe toujours n'a pas cet effet, car personne d'autre ne peut créer de dépôt au sein de votre compte.
GitHub prévoit bien une protection contre ce risque, mais celle-ci est plus limitée que la plupart des gens ne le pensent. La suppression d’un espace de noms verrouille définitivement une combinaison « propriétaire + nom de dépôt » afin qu’elle ne puisse plus être réutilisée, et cela concerne les dépôts qui comptaient plus de 100 clones ou plus de 100 utilisations de GitHub Actions au cours de la semaine précédant le changement de nom ou la suppression, ainsi que tout élément contenant une action répertoriée sur GitHub Marketplace.
Ce qui signifie que la protection couvre les colis qui préoccupent déjà tout le monde, mais laisse de côté les cas marginaux.
Dans le cas spécifique de Go, cette « longue traîne » s’avère énorme, et la même étude qui a recensé ces plus de 15 000 dépôts en a expliqué la raison. Le miroir de modules de Go récupère un dépôt une seule fois, puis met cette copie à la disposition de tous les autres utilisateurs. Un module peut être à l’origine de milliers d’appels « go get » sans que ces téléchargements servis par le proxy ne soient enregistrés comme des clones sur GitHub ; ainsi, une bibliothèque très utilisée peut rester en dessous du seuil de clonage qui, autrement, protégerait son espace de noms. Pour une bibliothèque Go ordinaire, qui n’est ni une action GitHub ni disponible sur le Marketplace, le nombre de clones sous-estime considérablement son utilisation en aval.
Une bibliothèque d’utilitaires comportant 40 clones par semaine, importée de manière transitive dans quelques centaines de projets, reste de toute façon bien en deçà du seuil. Ce sont là les chemins qui nécessitent réellement un audit, et ce sont aussi ceux que personne ne lit, car ils se trouvent à quatre niveaux de profondeur dans l’arborescence des dépendances de quelqu’un d’autre.
La mise hors service est évaluée au moment où le compte est renommé ou supprimé, et non de manière continue. Un dépôt qui était populaire il y a deux ans et qui est resté inactif depuis lors peut ne pas avoir atteint le seuil requis au cours de la semaine concernée. Il n'existe ni API permettant de vérifier cet état, ni liste publique ; le seul moyen de s'en assurer est donc d'essayer de créer le dépôt et de voir si GitHub répond que le nom a été mis hors service et ne peut pas être réutilisé.
Pourquoi la base de données de sommes de contrôle ne peut pas garantir la validité d'une nouvelle version
L'infrastructure de somme de contrôle de Go est vraiment excellente, bien meilleure que celle de la plupart des autres écosystèmes. Savoir exactement ce qu'elle garantit, et jusqu'où s'étend cette garantie, fait toute la différence entre se sentir en sécurité et l'être réellement.
sum.golang.org conserve un historique des hachages de modules, accessible au public et ne pouvant être que complété. Lorsqu’une compilation identifie une version de module public qui ne figure pas encore dans go.sum, la chaîne d’outils recherche ce hachage dans le journal avant de l’enregistrer localement, afin que le premier téléchargement ne soit pas effectué sans vérification. Les compilations suivantes effectuent une comparaison avec ce qui est déjà enregistré, et la commande `go mod verify` vérifie que les copies présentes dans votre cache de modules local n’ont pas été modifiées depuis leur téléchargement.
Tout cet ensemble de systèmes est très performant dans un domaine précis : il garantit que toute personne qui consulte example.com/[email protected] reçoive exactement les mêmes octets, aujourd’hui comme dans cinq ans. Si l’on republie un contenu différent dans une version qui a déjà été enregistrée, la divergence apparaît clairement.
Le « repojacking » n’affecte en rien une version enregistrée. L’attaquant publie une toute nouvelle version, voire un chemin d’accès entièrement nouveau, et la base de données des sommes de contrôle fonctionne exactement comme prévu. Dans le cas d’une version véritablement nouvelle, le contenu fourni par l’attaquant peut devenir le contenu enregistré pour ce module et cette version, et sera dès lors authentifié fidèlement pour tous les utilisateurs en aval. La somme de contrôle est authentique. L’entrée du journal est authentique. Rien dans l’un ou l’autre n’indique que le code provient du responsable de maintenance auquel vous faisiez initialement confiance.
| Scénario | Hachage précédent pour cette version | Prise de contrôle détectée |
| Version enregistrée republiée avec du nouveau contenu | Oui | Oui, la somme de contrôle ne correspond pas |
| Nouvelle version mineure d'un chemin détourné | Non, une toute nouvelle version | Non |
| Nouvelle dépendance ajoutée à la suite d'un rachat | Non | Non |
| La dépendance transitive a dépassé le seuil de prise de contrôle | Non, une toute nouvelle version | Non |
Il suffit de mettre à jour une dépendance ou d'en ajouter une nouvelle pour que la chaîne d'outils puisse prouver que les octets sont bien les mêmes que ceux que tout le monde obtient. Cela ne revient pas à prouver qu'ils ont leur place dans votre build.
Le proxy de modules disponible à l'adresse proxy.golang.org est utile dans ce cas, dans une certaine mesure. Le miroir conserve les versions qu’il a déjà récupérées et peut continuer à les fournir même après leur disparition en amont ; ainsi, une version récupérée avant une prise de contrôle reste disponible et inchangée, même si le dépôt est par la suite supprimé ou remplacé. Il s’agit là d’une véritable propriété de sécurité. Elle ne s’applique toutefois qu’aux versions déjà mises en cache avant la prise de contrôle et n’a aucune incidence sur la version suivante.
Il reste alors la question à laquelle aucune somme de contrôle ne peut répondre : celle de savoir si le contenu affiché lors de la première résolution est digne de confiance. L’examen d’un module avant sa résolution, puis sa recompilation à partir du code source afin de le comparer au contenu fourni par le chemin d’accès, constitue un contrôle différent intervenant plus tôt dans la séquence. C’est cette couche que représente SecureChain pour Go ajoute en amont du proxy.
Les chemins d'importation Vanity ouvrent une deuxième voie
Le « repojacking » visant les noms d'utilisateur GitHub est la variante qui a été baptisée et qui a fait l'objet de recherches. La variante qui retient beaucoup moins l'attention concerne les domaines personnalisés.
Go prend en charge les chemins d'importation personnalisés via des balises meta HTML. La résolution de example.com/mylib redirige la chaîne d'outils vers https://example.com/mylib?go-get=1, qui renvoie une balise meta « go-import » indiquant l'emplacement réel dans le système de contrôle de version (VCS), et la chaîne d'outils suit ce chemin. C'est ainsi que fonctionne golang.org/x/…, et que les entreprises publient des modules sous leur propre domaine.
Le mode d'exploitation s'explique de lui-même, principalement parce qu'il ne nécessite pas qu'un attaquant fasse preuve d'ingéniosité. Si le domaine expire, la prochaine personne qui l'enregistre prend le contrôle de tous les chemins d'accès aux modules qui s'y trouvent, et peut rediriger ces chemins vers n'importe quelle destination de son choix. Il n'y a ici aucun seuil de nombre de clones, aucune suppression d'espace de noms, et GitHub n'intervient absolument pas dans le processus.
De petits cabinets de conseil, des start-ups disparues, des projets open source menés par une seule personne : voilà ce à quoi on s'expose. Un nom de domaine expiré est également moins cher et plus discret à acquérir qu'un nom d'utilisateur GitHub chargé d'un passé.
go list -m -f ‘{{.Path}}’ all \
| grep -v ‘^github.com/\|^golang.org/\|^gopkg.in/’ \
| cut -d/ -f1 | sort -u
Vous obtenez ainsi tous les hôtes non évidents à partir desquels votre build s'effectue. Identifiez qui contrôle chacun de ces domaines et surveillez leur statut d'enregistrement, car un domaine dont la date d'expiration approche, ou qui semble simplement abandonné, constitue une dépendance assortie d'une date butoir.
Vérification de vos chemins d'accès aux modules pour détecter les risques de prise de contrôle
Deux vérifications, toutes deux rapides. Effectuez-les sur tous les dépôts Go de votre organisation, et pas seulement sur le service phare que tout le monde surveille déjà.
Commencez par signaler les URL de dépôts GitHub qui ne renvoient plus de réponse indiquant que le dépôt est actif.
go list -m -f ‘{{.Path}}’ all | grep ‘^github.com/’ \
| cut -d/ -f1-3 | sort -u \
| while read p; do
printf ‘%s %s\n’ “$(curl -s -o /dev/null -w ‘%{http_code}’ “https://$p”)” “$p”
done | grep -v ‘^200’
Un code 404 est un signal hautement prioritaire indiquant que le chemin d’accès n’est plus accessible au public. Il convient de vérifier cette situation avant de la considérer comme un risque avéré de « repojacking », car cela peut également signifier que le dépôt est désormais privé. Un code 301 indique généralement un changement de nom ou un transfert de compte, et la vérification ne suit délibérément pas les redirections afin que le statut affiché corresponde à ce que vous voyez. Dès qu’un attaquant s’empare d’un chemin d’accès, le statut revient à 200 ; cela permet donc de détecter la situation avant la prise de contrôle plutôt qu’après.
Regarde ensuite ce qui a été laissé de côté parmi les chemins qui mènent à une solution.
go list -m -u all | grep ‘\[‘
Cela permet d'identifier les modules pour lesquels des versions plus récentes sont disponibles, ce qui constitue un point de départ plutôt qu'une réponse définitive. Lorsqu'un module en est à une version plusieurs versions en retard alors que le développeur en amont continue de publier des mises à jour, il convient de recouper cette information avec l'activité réelle du dépôt.
Intégrez la vérification des erreurs 404 dans CI à un rythme hebdomadaire plutôt que de la considérer comme un audit ponctuel. Un compte qui détient aujourd’hui l’un de ces dépôts peut être supprimé ou renommé le mois prochain, et le délai avant que quelqu’un ne réclame l’ancien nom d’utilisateur constitue l’avertissement gratuit dont vous bénéficiez.
Savoir comment gérer concrètement un module dont le responsable en amont s’est définitivement retiré est une question plus complexe que celle de le retrouver. Intégrer le code signifie que votre équipe devient désormais responsable de ses CVE, et la plupart des organisations qui choisissent cette voie ne disposent pas du personnel nécessaire pour cela. Le portage en amont de correctifs vers un code dont le responsable en amont s’est détourné est une discipline pointue, axée sur les tests de régression et la compatibilité comportementale plutôt que sur les nouvelles fonctionnalités ; c’est généralement pour cette raison qu’elle finit par ne plus relever de la compétence d’une équipe produit.
Ce qu'il faut modifier dans vos builds Go
Go ne dispose pas de hook de cycle de vie de type npm, ni d’équivalent à « postinstall » ; par conséquent, le téléchargement d’une dépendance ne fournit pas à un attaquant un point d’exécution gratuit. Il s’agit là d’un véritable avantage par rapport à npm et PyPI.
Cet avantage a toutefois ses limites. Le code d'un module Go finit tout de même par s'exécuter, dès qu'un élément qui l'importe est compilé, testé ou exécuté, généralement via une fonction `init()` déclenchée au démarrage. Le déclenchement automatique au moment de l'installation disparaît. Le chemin d'exécution, lui, demeure, ce qui constitue un problème distinct et non pas un problème mineur.
Par où commencer dépend de votre situation actuelle. Si les chemins d’accès aux modules n’ont jamais fait l’objet d’un audit, lancez cette semaine la vérification 404 sur tous vos dépôts, car une heure de travail suffit pour obtenir une liste concrète sur laquelle s’appuyer. Si vos dépendances incluent des modules hébergés sur des comptes GitHub personnels, intégrez-les à l’aide de la commande `go mod vendor` et validez le résultat. Cela permet de placer le contenu validé de vos dépendances dans votre propre dépôt, de sorte que les compilations utilisant le répertoire `vendor` ne récupèrent jamais ces versions à partir d’un chemin d’accès susceptible de changer de mains.
Si vous résolvez des modules à partir de domaines personnalisés, vérifiez l'état d'enregistrement de chacun d'entre eux, car un domaine personnalisé dont l'enregistrement a expiré représente une prise de contrôle plus importante qu'un simple nom d'utilisateur et ne bénéficie d'aucun seuil de protection. Si vous utilisez GOPRIVATE ou GONOSUMDB, examinez attentivement les règles. GONOSUMDB exclut les modules correspondants de la vérification par base de données de sommes de contrôle, et GOPRIVATE utilise cette exclusion par défaut à moins que vous ne la remplaçiez ; ainsi, un caractère générique plus large que prévu supprime discrètement la vérification par base de données de sommes de contrôle pour davantage de modules que ceux que vous souhaitiez exclure. Et si Go coexiste avec npm, PyPI, Maven ou crates.io au sein de votre organisation, définissez une politique unique pour l’ensemble de ces plateformes, car les attaquants opèrent à travers les écosystèmes et le fait de bien sécuriser l’un d’entre eux ne fait que déplacer le problème ailleurs.
Il ne s'agit en aucun cas d'une solution ponctuelle. Un module qui est sûr aujourd'hui parce que son responsable est encore actif n'est pas assuré de le rester.
L'exposition dépend fortement de la part de votre infrastructure gérée par des comptes d’entreprise par rapport aux comptes personnels. Un service Go s’appuyant principalement sur golang.org/x, les principaux SDK cloud et les projets de la CNCF sera généralement moins exposé à ce problème particulier. Un service qui a intégré six bibliothèques utilitaires gérées par un seul développeur en 2019 a du pain sur la planche, et c’est en effectuant cet audit que vous pourrez identifier les dépendances nécessitant une attention particulière.
Le rôle de SecureChain for Go
Les vérifications ci-dessus n'empêchent pas une prise de contrôle de se produire. Elles vous indiquent où se situent vos vulnérabilités, ce qui est utile, mais ne revient pas à une véritable prévention. La lacune qui subsiste consiste à déterminer si une nouvelle version authentifiée d'un module mérite réellement la confiance, plutôt que de se contenter de confirmer que tout le monde a reçu les mêmes octets, et c'est précisément ce que fait SecureChain for Go a été conçu pour y remédier. Il recompile les modules à partir du code source, les analyse au moment de leur téléchargement et continue de corriger les vulnérabilités connues même lorsque le développeur en amont d’un module n’est plus actif. Vous trouverez plus de détails sur la page du produit, ainsi que la newsletter de TuxCare est à votre disposition si vous préférez suivre de près les recherches sur la chaîne d’approvisionnement spécifiques à Go au fur et à mesure de leur publication.
FAQ
Qu'est-ce que le « repojacking » ?
Récupération du chemin d'accès à un dépôt source dont un projet dépend toujours, généralement après la suppression ou le changement de nom du compte d'origine. Ce chemin étant toujours référencé dans les fichiers de dépendances, le code publié à l'emplacement récupéré donne lieu à des builds qui s'appuient sur le dépôt d'origine.
Pourquoi le langage Go est-il particulièrement exposé au « repojacking » ?
Go identifie les modules par leur chemin VCS plutôt que par un nom enregistré associé à un enregistrement de propriété. Il n'existe pas de compte d'enregistrement détenant github.com/user/lib ; ainsi, lorsque le nom de compte sous-jacent devient disponible, la personne qui le revendique contrôle le chemin du module.
La base de données de sommes de contrôle de Go permet-elle d'empêcher le « repojacking » ?
Pas en soi. Cela garantit que toute personne téléchargeant une version donnée d’un module obtienne un contenu identique, y compris lors du premier téléchargement, lorsque le hachage est recherché dans le journal public. Ce que cela ne permet pas de déterminer, c’est si une toute nouvelle version publiée à partir d’un chemin piraté est fiable, car une version véritablement nouvelle publiée à partir de ce chemin peut devenir le contenu enregistré par rapport auquel tous les utilisateurs en aval effectuent ensuite leur authentification.
GitHub empêche-t-il la prise de contrôle des espaces de noms des dépôts ?
En partie, et principalement pour les dépôts populaires. La mise hors service d'un espace de noms verrouille une combinaison « propriétaire-nom de dépôt » lorsque le dépôt a enregistré plus de 100 clones ou plus de 100 utilisations de GitHub Actions au cours de la semaine précédente, ou s'il contient une action répertoriée sur le Marketplace. Les projets de plus petite envergure ne dépassent pas ce seuil, et leurs espaces de noms restent disponibles. Pour Go, le critère de clonage est encore moins strict, car le miroir du module peut générer des milliers de téléchargements sans créer de clones.
Comment puis-je identifier les dépendances Go susceptibles d'être réutilisées ?
Répertoriez les chemins d’accès aux modules à l’aide de la commande `go list -m -f ‘{{.Path}}’ all`, puis vérifiez si l’URL de chaque dépôt renvoie toujours une réponse valide. Une erreur 404 sur un chemin dont dépend votre build nécessite une analyse plus approfondie, car cela signifie généralement que le dépôt en amont n’existe plus, mais cela peut également indiquer qu’il est désormais privé. Dans tous les cas, il est recommandé de vérifier ce chemin avant de considérer qu’il est fiable, et il est préférable d’effectuer cette vérification de manière régulière plutôt qu’une seule fois.
Le « vendoring » offre-t-il une protection contre le « repojacking » ?
Oui, pour les dépendances déjà validées dans votre répertoire « vendor ». Le « vendoring » copie le contenu des dépendances dans votre dépôt, et le mode « vendor » de Go n’accède pas au réseau lors de la compilation. Cela ne protège toutefois pas les nouvelles dépendances ni les mises à jour de version, qui continuent d’être résolues à partir du chemin d’accès comme d’habitude.
Les modules Go exécutent-ils du code lors de leur installation ?
Les modules Go ne disposent pas de scripts de cycle de vie des dépendances comparables aux hooks d’installation de npm. Le code malveillant présent dans un module Go s’exécute dès qu’un élément qui l’importe est exécuté, qu’il s’agisse d’un test, d’un outil de compilation ou d’un binaire de production, généralement via une fonction `init()` qui se déclenche au démarrage.



