La plupart des grandes attaques de la chaîne d'approvisionnement de ces deux dernières années ont suivi le même schéma. Un développeur lance npm install, et une dépendance qu'il n'a jamais choisie exécute du code sur sa machine avant même qu'il ait écrit une seule ligne. npm le permet par conception, et revient aujourd'hui sur ce choix. Go ne l'a jamais permis. Cet article examine dans quelle mesure cette seule différence explique l'écart, où Go est réellement plus sûr, et où il fait face aux mêmes risques que Node. Chaque affirmation est sourcée.
En bref
Sécurité de la chaîne d'approvisionnement : Go vs Node.js en un coup d'œil
| Aspect | Go (Golang) | Node.js (npm) |
|---|---|---|
| Exécution de code à l'installation | Aucune. go get/go build n'exécutent aucun script de paquet. | preinstall/install/postinstall exécutent automatiquement du code arbitraire. |
| Quand le code malveillant s'exécute | Uniquement s'il est importé et que la fonction est appelée. | Dès l'installation, avant que vous ayez écrit une ligne. |
| Garantie d'intégrité | Journal de transparence des sommes de contrôle en arbre de Merkle (sum.golang.org), infalsifiable sans trace, pour toujours. | Hachages du lockfile plus une provenance plus récente. Historiquement plus faible. |
| Résolution des versions | Minimal Version Selection. Les mises à jour sont explicites. | Plages semver (^, ~). Un nouveau patch malveillant peut être résolu automatiquement. |
| Surface de dépendances | Bibliothèque standard étendue, moins de dépendances directes. | Culture des micro-modules, arbres transitifs tentaculaires. |
| Analyse des vulnérabilités | govulncheck fait une analyse d'atteignabilité, donc moins de fausses alertes. | npm audit signale tout l'arbre, ce qui entraîne une lassitude face aux alertes. |
| Modèle de registre | Décentralisé. Les modules sont des URL de sources. | Comptes centralisés. Un seul phishing expose tout un portefeuille. |
| Reste exposé à | Mainteneurs victimes de phishing, typosquats, mise en cache de malwares par le proxy. | Tout ce qui précède, plus les vers à base de scripts d'installation. |
Go l'emporte sur le comportement par défaut et la surface d'attaque. Un attaquant déterminé qui piège un mainteneur humain par phishing peut toujours passer, dans l'un comme dans l'autre écosystème.
Pourquoi Go échappe-t-il à l'attaque qui frappe le plus npm ?
Go n'a pas de scripts d'installation. Quand vous lancez npm install, chaque paquet de l'arbre transitif peut enregistrer des hooks de cycle de vie (preinstall, install, postinstall). npm les exécute automatiquement, avec les privilèges de votre utilisateur, avant que vous ayez exécuté ou même lu une seule ligne (npm scripts docs). GitHub a qualifié les scripts d'installation de plus grande surface d'exécution de code de tout l'écosystème npm (GitHub Security, 2025).
Go les a délibérément laissés de côté. Il n'a pas de hooks de build. go get récupère et vérifie le code source, go build le compile, et aucun des deux n'exécute de scripts définis par les paquets. Une dépendance Go piégée reste là sous forme de simple code source tant que votre code ne l'importe pas et n'appelle pas la fonction malveillante. Cette fenêtre est bien plus étroite et plus facile à repérer que du code qui s'exécute chez tout le monde à chaque installation.
Voici ce que fait chaque commande :
example.bashbash# npm: the postinstall hook runs on every install, automatically $ npm install left-pad > [email protected] postinstall > node ./scripts/setup.js # <- arbitrary code, your privileges, right now # go: nothing in the package gets to run during fetch or build $ go get example.com/some/module go: downloaded example.com/some/module v1.0.0 # source fetched, checksum verified, nothing executed
C'est à cause de cette différence que npm v12, qui sort en juillet 2026, bloque les scripts d'installation par défaut, et que pnpm a déjà fait de même dans sa v10 (npm scripts docs). L'outillage JavaScript se rapproche du comportement que Go a depuis son lancement.
Quelle est l'ampleur du problème de la chaîne d'approvisionnement npm, en chiffres ?
npm est de loin la cible principale. Sonatype a identifié 454 648 nouveaux paquets malveillants en 2025, ce qui a porté son total cumulé de paquets bloqués au-delà de 1,23 million, soit une hausse de 75 % sur un an. Plus de 99 % de ces malwares open source se trouvaient sur npm (Sonatype 11th State of the Software Supply Chain, 2026). Son index des malwares du quatrième trimestre 2025 chiffrait cette part à 99,8 % des malwares bloqués sur la période.
Il n'existe aucun décompte publié des modules Go malveillants. Sonatype, l'OpenSSF et la plupart des éditeurs ne suivent pas Go comme un écosystème distinct dans leurs index de malwares, faute d'incidents suffisants pour l'indexer. Ce vide dans les données en dit long à lui seul.
Où se trouvaient les malwares open source en 2025 (part des nouveaux paquets malveillants, par écosystème) :
| Écosystème | Part des malwares open source en 2025 |
|---|---|
| npm | Plus de 99 % |
| Tous les autres (Go compris)* | Moins de 1 % |
*454 648 nouveaux paquets malveillants ont été identifiés en 2025. Go n'est pas suivi comme un écosystème distinct, faute d'incidents suffisants pour l'indexer. Source : Sonatype 11th State of the Software Supply Chain, 2026.
Que s'est-il réellement passé lors de la vague de vers npm de 2025 et 2026 ?
Une série de vers auto-propagateurs a transformé un risque connu en urgence permanente, et tous ont utilisé des scripts d'installation. npm connaît des incidents retentissants depuis des années. En 2018, event-stream a caché un voleur de portefeuilles Bitcoin dans une dépendance téléchargée environ 8 millions de fois. En 2021, ua-parser-js a distribué des cryptomineurs après une prise de contrôle de compte. Mais c'est en 2025 que les incidents ont commencé à s'enchaîner.
| Date | Incident | Ce qui s'est passé |
|---|---|---|
| 8 sept. 2025 | Phishing de qix | 18 paquets détournés, dont chalk et debug. Une exposition d'environ 2,6 milliards de téléchargements hebdomadaires. |
| Sept. 2025 | Shai-Hulud | Premier ver npm. Un hook postinstall collectait des identifiants et s'injectait dans une centaine de paquets supplémentaires par victime. |
| 24 nov. 2025 | Shai-Hulud 2.0 | Passage à preinstall, avec l'ajout d'un effacement du répertoire personnel. Environ 796 paquets, retrouvés dans 27 % des environnements cloud analysés. |
| 31 mars 2026 | axios | Des acteurs nord-coréens ont manipulé le mainteneur par ingénierie sociale. Un RAT en postinstall a déclenché des connexions C2 dans plus de 12 000 projets. |
| Juin 2026 | Miasma | A contourné le blocage des scripts d'installation de npm grâce à la technique « Phantom Gyp », une recompilation node-gyp implicite. |
La compromission de qix en septembre 2025 a commencé par un e-mail convaincant de réinitialisation de la 2FA, envoyé depuis le domaine usurpé npmjs.help. L'attaquant a pris le contrôle du compte du mainteneur Josh Junon et publié des versions malveillantes de 18 paquets. Parmi eux figuraient chalk (~300 millions de téléchargements par semaine) et debug (~358 millions), pour une exposition cumulée de plus de 2,6 milliards de téléchargements hebdomadaires. La charge utile était un crypto-clipper côté navigateur, et elle est restée en ligne pendant environ deux heures.
Quelques jours plus tard est arrivé Shai-Hulud, le premier véritable ver npm. À l'installation, son bundle.js collectait les identifiants npm, GitHub, AWS et GCP, et lançait TruffleHog pour aspirer les secrets. Il utilisait ensuite les jetons npm volés pour s'injecter dans jusqu'à une centaine de paquets supplémentaires appartenant à chaque victime. La CISA a publié une alerte (CISA, 2025). Sonatype attribue 171 740 paquets malveillants aux campagnes npm auto-répliquantes sur quelques mois.
Shai-Hulud 2.0 (24 novembre 2025) a déplacé l'exécution vers preinstall pour toucher davantage de machines. Il installait le runtime Bun pour échapper à la surveillance basée sur Node et ajoutait une solution de repli destructrice capable d'effacer un répertoire personnel. Wiz a trouvé des paquets touchés dans environ 27 % des environnements cloud qu'il a analysés (Wiz, 2025).
En 2026, il est devenu clair que bloquer les scripts d'installation ne suffirait pas à lui seul. La compromission d'axios (31 mars 2026) n'a pas commencé par un mot de passe volé par phishing. Des acteurs liés à la Corée du Nord (suivis sous les noms UNC1069 / Sapphire Sleet) ont ciblé le mainteneur principal avec une fausse entreprise, un espace de travail Slack à son image et un appel Teams qui a installé un RAT sur la machine du mainteneur. Ils ont ensuite publié des versions malveillantes d'axios (plus de 100 millions de téléchargements hebdomadaires) embarquant un RAT en postinstall. StepSecurity a détecté des connexions C2 anormales dans plus de 12 000 projets (StepSecurity, 2026). Puis Miasma (juin 2026) a contourné le futur blocage des scripts d'installation de npm grâce à la technique « Phantom Gyp ». Le paquet embarque un fichier binding.gyp, et la recompilation node-gyp implicite de npm exécute la charge utile sans aucun script déclaré.
Go est-il donc une solution miracle ? Pas tout à fait
Les comportements par défaut de Go bloquent toute une classe d'attaques, mais des attaquants s'en sont tout de même pris à Go à quelques reprises. Les modules Go malveillants documentés en 2025 se comptent en quelques dizaines, répartis sur une poignée de campagnes. Face aux centaines de milliers de npm, c'est minuscule. Le cas le plus notable mérite d'être détaillé, car il montre tout le travail qu'un attaquant doit fournir pour contourner la conception de Go.
La backdoor boltdb-go/bolt a été révélée en février 2025, mais elle avait été implantée dès novembre 2021. Elle usurpait par typosquatting le module BoltDB populaire (github.com/boltdb/bolt), dont dépendent des milliers de paquets et qui était utilisé chez Shopify et Heroku, et elle embarquait une backdoor de commande et contrôle. L'attaquant a publié la version malveillante v1.3.1, a laissé le Go Module Mirror la mettre en cache, puis a réécrit le tag Git pour qu'il pointe de nouveau vers du code sain. Quiconque auditait le dépôt sur GitHub voyait du code sain, tandis que le proxy continuait de servir la backdoor. Cela a fonctionné, mais uniquement en exploitant un cas limite du système de cache. Sur npm, un hook d'installation aurait fait le travail sans aucun effort de ce genre (Socket, 2025).
Quelques autres campagnes sont apparues en 2025. En mars, une vague de typosquats hypert et layout a diffusé un malware de type loader visant des développeurs du secteur financier. Il y a aussi eu quelques modules effaceurs de disque et un voleur d'identifiants SSH. Tous ces cas étaient isolés, et chacun exigeait qu'un développeur tape un mauvais chemin d'import. Aucun ne s'exécutait automatiquement.
Lorsqu'un module malveillant est signalé, l'équipe sécurité de Go le retire du proxy, qui renvoie alors une 403 SECURITY ERROR, et l'ajoute à la base de vulnérabilités Go. Pour boltdb-go, Google a retiré le module du proxy et de GitHub, et l'a consigné dans la base de vulnérabilités. L'équipe a aussi mentionné des travaux en cours sur l'analyse des capacités avec Capslock et sur des comparaisons avec deps.dev. Les défenses de Go rendent les attaques bien plus coûteuses, mais elles ne garantissent pas la sécurité, pas plus que celles de n'importe quel autre écosystème.
Qu'est-ce qui rend Go structurellement plus sûr ?
Outre l'absence de scripts d'installation, Go fait quatre autres choix de conception qui renforcent cet avantage.
La base de sommes de contrôle de Go est exceptionnellement solide. Votre go.sum enregistre les hachages SHA-256 de chaque dépendance. sum.golang.org est un journal de transparence en arbre de Merkle, dans l'esprit de Certificate Transparency. Il enregistre le hachage de chaque version de module la première fois que quelqu'un la récupère et le conserve pour toujours (Go module reference). La commande go vérifie les preuves d'inclusion et de cohérence avant de faire confiance à du code, si bien qu'un tag Git réécrit par force-push ou un proxy qui altère les données échoue bruyamment. Le cryptographe Filippo Valsorda, qui a dirigé l'équipe sécurité de Go chez Google, soutient que Go offre la meilleure garantie d'intégrité des paquets de tous les écosystèmes de langages, car chaque client dans le monde résout une version donnée d'un module vers les mêmes octets, pour toujours (Filippo Valsorda). Le journal a une limite. Il prouve la cohérence, pas la qualité du code, et il n'est utile que si quelqu'un le surveille.
Minimal Version Selection ralentit la propagation des mauvaises versions. Les builds Go utilisent la version la plus basse qui satisfait toutes les exigences, et les mises à jour sont explicites (MVS reference). Avec les plages ^ et ~ de npm, un patch malveillant fraîchement publié peut se retrouver automatiquement dans un build. En Go, une nouvelle version piégée ne se propage pas en aval tant qu'une personne n'a pas délibérément relevé l'exigence. Les vers qix et Shai-Hulud reposaient précisément sur ce comportement de mise à jour automatique que MVS n'a pas.
govulncheck s'appuie sur l'analyse d'atteignabilité pour réduire les fausses alertes. Le scanner officiel de Go consulte la base de vulnérabilités curée sur vuln.go.dev et n'alerte que si votre code appelle réellement le symbole vulnérable (govulncheck, Go blog). npm audit signale chaque version vulnérable n'importe où dans l'arbre, que vous l'atteigniez ou non, et les développeurs apprennent à l'ignorer.
Il n'existe pas de compte central dont la prise de contrôle expose tout un portefeuille. Les modules Go sont identifiés par l'URL de leur source, ils reposent donc sur la sécurité des comptes GitHub (ou GitLab). Sur npm, un seul compte compromis expose tout ce que possède le mainteneur. Cette différence explique en partie pourquoi les vers npm se propagent comme ils le font alors que les incidents Go restent circonscrits.
La bibliothèque standard plus étendue aide aussi. HTTP, JSON, la cryptographie et les templates sont fournis avec Go, si bien qu'un projet typique a moins de dépendances directes et moins de mainteneurs à qui faire confiance. Une étude de 2025 a certes montré que l'amplification par dépendance de Go (environ 4,48x) est proche de celle de npm (environ 4,32x), donc chaque paquet Go n'entraîne pas moins de dépendances transitives qu'un paquet npm. Go prend l'avantage parce que les projets démarrent avec moins de dépendances directes, ce qui réduit le nombre de personnes auxquelles vous faites confiance.
Ce que les comportements par défaut de Go ne couvrent pas
Go ferme automatiquement les plus grandes portes. Les risques ci-dessous concernent tous les écosystèmes, Go compris, et c'est donc à vous de les couvrir.
- Un mainteneur victime de phishing peut contourner les défenses de n'importe quel écosystème. Si le compte GitHub d'un mainteneur est compromis, l'attaquant peut tagger une version malveillante, et la base de sommes de contrôle l'enregistre fidèlement, car elle ne sait pas distinguer le bon code du mauvais. Une attaque à la axios fonctionne contre tous les écosystèmes, et c'est pourquoi l'industrie se tourne vers les clés matérielles et le trusted publishing.
- Vous choisissez toujours vos dépendances par leur nom. La vérification des sommes de contrôle de Go empêche l'altération d'un module que vous avez choisi, mais elle ne peut pas vous empêcher de choisir un typosquat. Vérifiez le chemin d'import par rapport au dépôt canonique avant d'ajouter une dépendance.
- L'immuabilité du proxy est surtout une fonctionnalité. Le cache qui garantit que chaque build obtient des octets identiques est aussi ce qui a gardé la backdoor boltdb-go accessible après le nettoyage du tag Git. Ce cas était rare, et le processus de retrait de l'équipe Go ainsi que la base de vulnérabilités le couvrent.
- Les comportements par défaut protègent l'installation, pas l'exécution. L'avantage de Go, c'est que rien ne s'exécute pendant la récupération ou le build. Une fois que vous importez et appelez une dépendance, elle s'exécute avec vos privilèges, comme dans n'importe quel langage. Isoler du code non fiable à l'exécution est un problème distinct dans tous les écosystèmes.
- Laissez la protection activée. La seule erreur que l'on s'inflige soi-même consiste à définir
GOSUMDB=offde manière globale, ce qui désactive la vérification des sommes de contrôle décrite plus haut. Laissez-la activée et limitezGOPRIVATEaux seuls chemins réellement internes.
Comment les deux écosystèmes convergent-ils vers les mêmes correctifs ?
Les deux écosystèmes adoptent les mêmes défenses, car dans les deux cas le maillon faible, ce sont les personnes. Après la vague de 2025, GitHub a annoncé la 2FA obligatoire avec FIDO/WebAuthn, des jetons granulaires à courte durée de vie et l'abandon des anciens jetons classiques. GitHub pousse aussi le trusted publishing via OIDC pour une provenance de build cryptographique (GitHub Security, 2025). npm v12 (juillet 2026) bloque les scripts d'installation par défaut et ajoute un délai de carence min-release-age, si bien qu'un paquet en ligne pendant seulement deux heures ne vous atteint jamais.
Ces changements aident. Mais axios a montré où ils cessent de fonctionner. Aucune politique de jetons n'arrête un mainteneur dont l'ordinateur portable exécute un RAT. Seules des clés matérielles FIDO2 combinées à des installations à provenance vérifiée et soumises à un délai de carence l'auraient fait. Les deux communautés apprennent que les attaquants visent le mainteneur plus que l'outillage. Go garde là encore un avantage. Même quand un mainteneur est compromis, les dégâts sont moindres, car rien ne s'exécute à l'installation.
Que faire dès maintenant ?
Les étapes dépendent de votre stack.
Si vous écrivez du Go :
- Ne définissez jamais
GOSUMDB=offouGONOSUMCHECKde manière globale. LimitezGOPRIVATEstrictement aux chemins réellement internes. - Commitez
go.sumet compilez avec-mod=readonly. - Exécutez
govulncheck ./...en CI comme garde-fou tenant compte de l'atteignabilité. - Vérifiez les nouvelles dépendances pour détecter les typosquats. Contrôlez les chemins d'import par rapport au dépôt canonique avant de les ajouter.
- Surveillez les nouvelles versions de vos dépendances critiques avec Socket ou deps.dev.
Si vous écrivez du Node :
- Passez à npm 11.16.0+ et définissez
ignore-scripts=true, avec une liste d'autorisation (comme@lavamoat/allow-scripts) pour les rares paquets qui ont vraiment besoin de scripts. - Utilisez
npm ciavec un lockfile figé, épinglez des versions exactes et définissez un délai de carencemin-release-agede 3 à 7 jours, pour que les compromissions de deux heures ne vous atteignent jamais. - Adoptez le trusted publishing (OIDC) et les clés matérielles FIDO2. Ne comptez pas sur le TOTP pour la publication.
- Utilisez une véritable analyse de composition logicielle (Socket, Snyk) avec détection comportementale, pas seulement
npm audit. - Enregistrez publiquement vos noms de paquets internes, à titre défensif, pour bloquer la confusion de dépendances.
Questions fréquentes
Go est-il vraiment plus sûr que Node.js pour la sécurité de la chaîne d'approvisionnement ?
Oui, structurellement. La raison principale est que go get et go build n'exécutent aucun script au moment de l'installation, ce qui supprime le vecteur preinstall/postinstall à l'origine de presque tous les grands vers npm de 2025 et 2026. Plus de 99 % des malwares open source de 2025 sont apparus sur npm (Sonatype, 2026). Go est plus sûr, mais il n'est pas immunisé.
Quelle est la principale différence de sécurité entre Go et npm ?
L'exécution de code au moment de l'installation. Lors d'un npm install, npm exécute automatiquement des scripts de paquets arbitraires avec vos privilèges, pour chaque paquet de l'arbre. Go n'a aucun hook de build, donc une dépendance malveillante ne fait rien tant que votre code ne l'importe pas et ne l'appelle pas. C'est pourquoi npm v12 bloque désormais les scripts d'installation par défaut, ce qui correspond au comportement que Go a toujours eu.
Go a-t-il déjà subi une attaque de la chaîne d'approvisionnement ?
Oui. La backdoor boltdb-go usurpait BoltDB par typosquatting et a servi une backdoor d'accès à distance depuis le cache de modules de Go pendant trois ans (Socket, 2025). Une campagne hypert/layout de 2025 a diffusé au moins sept typosquats embarquant un malware de type loader. Ces incidents sont réels mais rares, et les modules malveillants sont retirés du proxy dès qu'ils sont signalés.
Qu'est-ce que la base de sommes de contrôle de Go et pourquoi est-ce important ?
sum.golang.org est un journal de transparence en arbre de Merkle. Il enregistre de façon permanente le hachage de chaque version de module la première fois que cette version est vue. La commande go vérifie ces preuves avant de faire confiance au code, si bien qu'une altération ou un tag Git réécrit échoue bruyamment (Go module reference). Chaque client obtient des octets identiques pour une version donnée, ce qui constitue la garantie d'intégrité la plus forte parmi les gestionnaires de paquets courants.
Bloquer les scripts d'installation npm règle-t-il le problème ?
Cela aide beaucoup, mais ne règle pas tout. L'attaque axios a utilisé un RAT en postinstall après avoir manipulé le mainteneur par ingénierie sociale, et la campagne Miasma a contourné le blocage des scripts via une recompilation node-gyp implicite. Le blocage des scripts, combiné à des clés matérielles FIDO2, à un délai de carence sur les nouvelles versions et à la vérification de provenance, comble l'essentiel de l'écart. Un mainteneur victime de phishing peut toutefois contourner n'importe quel contrôle pris isolément.
Faut-il passer de Node à Go uniquement pour la sécurité ?
La sécurité joue en faveur de Go, mais la plupart des équipes choisissent un langage pour tout ce qu'il apporte : la concurrence, le recrutement, l'écosystème et la vitesse à laquelle elles peuvent livrer. Go est un excellent langage backend, et aussi le plus sûr structurellement face aux attaques de la chaîne d'approvisionnement. Si vous l'envisagez déjà, ses comportements par défaut plus sûrs sont une raison de plus de l'apprendre.
Sources
Sources primaires citées dans cet article (dernière vérification le 29 juin 2026) :
- Sonatype : State of the Software Supply Chain
- Socket : Malicious Go module exploits proxy caching for persistence (boltdb-go)
- GitHub Security : Our plan for a more secure npm supply chain
- Go module reference : Checksum database
- Go module reference : Minimal Version Selection
- Go blog : govulncheck
- Go : Vulnerability management for Go
- Documentation npm : scripts et hooks de cycle de vie
- Alex Birsan : Dependency Confusion
- CISA : avis de cybersécurité
- Wiz : blog de recherche
- StepSecurity : blog
- Filippo Valsorda : words.filippo.io
