When Socket disclosed the PolinRider campaign in early July 2026, most headlines focused on npm. The numbers tell a different story: of the 108 unique malicious packages published by the North Korea–linked Contagious Interview cluster, 61 were Go modules — more than npm (19), Packagist (10) and Chrome extensions (1) combined. For the first time, a major state-sponsored supply chain campaign made the Go ecosystem its primary target.
Quand Socket a divulgué la campagne PolinRider début juillet 2026, la plupart des titres se sont concentrés sur npm. Les chiffres racontent une autre histoire : sur les 108 packages malveillants uniques publiés par le cluster nord-coréen Contagious Interview, 61 étaient des modules Go — plus que npm (19), Packagist (10) et les extensions Chrome (1) réunis. Pour la première fois, une campagne supply chain étatique majeure a fait de l'écosystème Go sa cible principale.
Go was long considered structurally safer than npm: no install scripts, an immutable module proxy, a cryptographically verifiable checksum database. Those defenses are real — but attackers have learned to work around them, and in one documented case turned Go's own proxy caching into a persistence mechanism that hid a backdoor for more than three years. This guide covers what changed, how Go's defenses actually work, and the concrete hardening steps every Go team should take in 2026.
Go a longtemps été considéré comme structurellement plus sûr que npm : pas de scripts d'installation, un module proxy immuable, une base de checksums vérifiable cryptographiquement. Ces défenses sont réelles — mais les attaquants ont appris à les contourner, et dans un cas documenté, ils ont transformé le cache du proxy Go en mécanisme de persistance qui a dissimulé une backdoor pendant plus de trois ans. Ce guide couvre ce qui a changé, comment fonctionnent réellement les défenses de Go, et les mesures concrètes de durcissement que chaque équipe Go devrait prendre en 2026.
PolinRider: Why Go Became the Primary Target
PolinRider : Pourquoi Go est Devenu la Cible Principale
PolinRider, active since December 2025 and attributed to the Contagious Interview / Famous Chollima activity cluster, does not rely on typosquatting alone. Its operators compromise legitimate GitHub repositories and plant malicious commits containing obfuscated loaders. The malicious code is frequently inserted as a single line padded with whitespace, pushing the executable payload beyond the default editor screen width so a quick code review sees nothing wrong.
PolinRider, actif depuis décembre 2025 et attribué au cluster Contagious Interview / Famous Chollima, ne repose pas uniquement sur le typosquatting. Ses opérateurs compromettent des dépôts GitHub légitimes et y insèrent des commits malveillants contenant des loaders obfusqués. Le code malveillant est fréquemment inséré sur une seule ligne remplie d'espaces, repoussant le payload exécutable au-delà de la largeur d'écran par défaut de l'éditeur pour qu'une revue de code rapide ne voie rien d'anormal.
The loaders hide in configuration files or fake .woff2 font files, execute through developer tooling such as VS Code tasks, and fetch encrypted second-stage payloads through public blockchain RPC infrastructure before delivering the DEV#POPPER remote access trojan or the OmniStealer information stealer. The end goal, according to Socket, is a persistent foothold inside enterprise CI/CD pipelines — turning the victim organization into a distributor of downstream supply chain attacks.
Les loaders se cachent dans des fichiers de configuration ou de fausses polices .woff2, s'exécutent via l'outillage développeur comme les tâches VS Code, et récupèrent des payloads de second étage chiffrés via des infrastructures RPC blockchain publiques avant de délivrer le RAT DEV#POPPER ou le stealer OmniStealer. L'objectif final, selon Socket, est un point d'ancrage persistant dans les pipelines CI/CD d'entreprise — transformant l'organisation victime en distributeur d'attaques supply chain en aval.
Why 61 Go modules? Because Go's ecosystem is decentralized by design. There is no central registry with a publish step, account 2FA, or malware scanning gate: any public Git repository instantly becomes an importable Go module. Compromising one GitHub repo — or creating a convincing lookalike namespace — is all it takes. Ecosystem-wide responses that npm rolled out in 2026 (install scripts blocked in npm v12, staged publishing, mandatory 2FA) simply have no equivalent enforcement point in Go.
Pourquoi 61 modules Go ? Parce que l'écosystème Go est décentralisé par conception. Il n'y a pas de registre central avec étape de publication, 2FA de compte ou scan antimalware : n'importe quel dépôt Git public devient instantanément un module Go importable. Compromettre un dépôt GitHub — ou créer un namespace sosie convaincant — suffit. Les réponses écosystème que npm a déployées en 2026 (scripts bloqués dans npm v12, publication par étapes, 2FA obligatoire) n'ont tout simplement pas de point d'application équivalent en Go.
Go's Decentralized Attack Surface: Namespace Confusion on pkg.go.dev
La Surface d'Attaque Décentralisée de Go : Confusion de Namespace sur pkg.go.dev
Because Go modules are imported directly from repository URLs, a search on pkg.go.dev can return several similarly named modules. Attackers craft namespaces that look trustworthy at a glance: github.com/boltdb-go/bolt instead of github.com/boltdb/bolt, or github.com/bpoorman/uuid mimicking Google's official UUID library. Socket documented that the fake bpoorman UUID packages had been silently stealing developer data for years before discovery.
Comme les modules Go sont importés directement depuis des URLs de dépôts, une recherche sur pkg.go.dev peut retourner plusieurs modules aux noms similaires. Les attaquants conçoivent des namespaces qui paraissent fiables au premier regard : github.com/boltdb-go/bolt au lieu de github.com/boltdb/bolt, ou github.com/bpoorman/uuid imitant la bibliothèque UUID officielle de Google. Socket a documenté que les faux packages UUID de bpoorman volaient silencieusement des données de développeurs pendant des années avant leur découverte.
Go does have one structural advantage over npm: go get never executes code at install time. There are no preinstall/postinstall hooks. But that protection ends the moment you build or run: malicious code executes on first import, and Go's runtime offers uniquely powerful primitives for attackers — cgo, dynamically loaded plugins, external binary execution and reflection-based dynamic invocation, all documented as viable attack vectors in the GoSurf academic analysis of Go supply chain attack surfaces.
Go conserve un avantage structurel sur npm : go get n'exécute jamais de code à l'installation. Il n'y a pas de hooks preinstall/postinstall. Mais cette protection s'arrête au moment du build ou de l'exécution : le code malveillant s'exécute au premier import, et le runtime Go offre des primitives particulièrement puissantes pour les attaquants — cgo, plugins chargés dynamiquement, exécution de binaires externes et invocation dynamique par réflexion, tous documentés comme vecteurs viables dans l'analyse académique GoSurf des surfaces d'attaque supply chain de Go.
The Module Proxy Cache Trap: How boltdb-go Hid a Backdoor for 3 Years
Le Piège du Cache Module Proxy : Comment boltdb-go a Caché une Backdoor Pendant 3 Ans
The Go Module Proxy (proxy.golang.org) caches every module version it serves, immutably and indefinitely. That immutability is normally a security feature — a published version can never be silently altered. In February 2025, Socket revealed how attackers weaponized it: a typosquat of BoltDB (github.com/boltdb-go/bolt, impersonating a module with 8,367 dependent packages) was published in November 2021 with a backdoor enabling remote command execution via a hidden C2 domain.
Le Go Module Proxy (proxy.golang.org) met en cache chaque version de module qu'il sert, de manière immuable et indéfinie. Cette immuabilité est normalement une fonctionnalité de sécurité — une version publiée ne peut jamais être altérée silencieusement. En février 2025, Socket a révélé comment des attaquants l'ont retournée contre les développeurs : un typosquat de BoltDB (github.com/boltdb-go/bolt, imitant un module dont dépendent 8 367 packages) a été publié en novembre 2021 avec une backdoor permettant l'exécution de commandes à distance via un domaine C2 caché.
The trick: after the malicious version was cached by the Module Proxy, the attackers rewrote the Git tag on GitHub to point at a clean version. Anyone auditing the source repository saw harmless code — while go get, which downloads from the proxy by default, kept serving the original backdoored payload. The deception went undetected for over three years. If this pattern sounds familiar, it should: the Laravel-Lang attack of May 2026 used the same git-tag-rewrite technique against Composer.
L'astuce : après la mise en cache de la version malveillante par le Module Proxy, les attaquants ont réécrit le tag Git sur GitHub pour pointer vers une version propre. Quiconque auditait le dépôt source voyait du code inoffensif — tandis que go get, qui télécharge depuis le proxy par défaut, continuait de servir le payload backdooré d'origine. La supercherie est restée indétectée pendant plus de trois ans. Si ce schéma vous semble familier, c'est normal : l'attaque Laravel-Lang de mai 2026 a utilisé la même technique de réécriture de tags Git contre Composer.
The lesson is uncomfortable but essential: auditing the GitHub repository is not the same as auditing what you actually download. Your build pulls from the proxy cache, and the proxy cache answers to no one's git history.
La leçon est inconfortable mais essentielle : auditer le dépôt GitHub n'est pas la même chose qu'auditer ce que vous téléchargez réellement. Votre build tire depuis le cache du proxy, et le cache du proxy ne rend de comptes à l'historique git de personne.
Go's Built-In Defenses: go.sum and the Checksum Database
Les Défenses Intégrées de Go : go.sum et la Base de Checksums
Go's answer to package integrity predates most of the industry's attestation work. The checksum database at sum.golang.org, operated by Google, is a global append-only, cryptographically verifiable log of go.sum entries. When go get adds a dependency, it fetches the expected hash from the sumdb along with a cryptographic proof of the log's integrity. The result: every build of a given module version, anywhere in the world, uses byte-identical dependency contents.
La réponse de Go à l'intégrité des packages précède la plupart des travaux d'attestation de l'industrie. La base de checksums sum.golang.org, opérée par Google, est un journal global en append-only, vérifiable cryptographiquement, des entrées go.sum. Quand go get ajoute une dépendance, il récupère le hash attendu depuis la sumdb avec une preuve cryptographique de l'intégrité du journal. Résultat : chaque build d'une version de module donnée, partout dans le monde, utilise un contenu de dépendances identique à l'octet près.
This is genuinely strong protection against tampering — it makes a TanStack-style attack (republishing altered versions) or lockfile poisoning far harder in Go than in npm. But understand what it does not protect against: if the module was malicious from its very first publication (BoltDB typosquat, all 61 PolinRider modules), the checksum database faithfully guarantees you receive the malware unaltered. Integrity is not trust.
C'est une protection réellement solide contre la falsification — elle rend une attaque de type TanStack (republication de versions altérées) ou l'empoisonnement de lockfile bien plus difficile en Go qu'en npm. Mais comprenez ce contre quoi elle ne protège pas : si le module était malveillant dès sa première publication (typosquat BoltDB, les 61 modules PolinRider), la base de checksums vous garantit fidèlement de recevoir le malware non altéré. L'intégrité n'est pas la confiance.
# Verify that your module cache matches go.sum
go mod verify
# Inspect where a module actually comes from
go mod download -x github.com/boltdb/bolt
# For private/internal modules: skip proxy + sumdb (and nothing else!)
go env -w GOPRIVATE=*.corp.example.com
One common misconfiguration deserves a warning: setting GOFLAGS=-mod=mod, GONOSUMCHECK or a blanket GONOSUMDB=*/GOFLAGS="-insecure" to "fix" a CI error disables exactly the verification layer that makes Go resilient. Scope GOPRIVATE to your internal domains only, and treat any global checksum bypass in CI as a security incident.
Une erreur de configuration courante mérite un avertissement : définir GOFLAGS=-mod=mod, GONOSUMCHECK ou un GONOSUMDB=*/GOFLAGS="-insecure" global pour « réparer » une erreur CI désactive exactement la couche de vérification qui rend Go résilient. Limitez GOPRIVATE à vos domaines internes uniquement, et traitez tout bypass global de checksums en CI comme un incident de sécurité.
govulncheck: Reachability-Based Scanning (and Its Limits)
govulncheck : Scan Basé sur l'Atteignabilité (et Ses Limites)
govulncheck is Go's official vulnerability scanner, backed by the curated Go Vulnerability Database (vuln.go.dev). Unlike most SCA tools that flag every CVE in your dependency tree, govulncheck performs call-graph reachability analysis: it only reports vulnerabilities in functions your code actually (transitively) calls. That makes it exceptionally low-noise — ideal as a blocking CI gate.
govulncheck est le scanner de vulnérabilités officiel de Go, adossé à la Go Vulnerability Database curée (vuln.go.dev). Contrairement à la plupart des outils SCA qui signalent chaque CVE de votre arbre de dépendances, govulncheck effectue une analyse d'atteignabilité par graphe d'appels : il ne rapporte que les vulnérabilités dans des fonctions que votre code appelle réellement (transitivement). Cela le rend exceptionnellement peu bruyant — idéal comme gate CI bloquante.
# Install and run govulncheck
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
# Scan a compiled binary (works without source)
govulncheck -mode=binary ./bin/myservice
# CI example (GitHub Actions step)
- name: Vulnerability scan
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
Two limits matter. First, reachability analysis is conservative — it can report a vulnerability as reachable when it is not, and per Go's own guidance it should be treated as a powerful first filter, not a complete answer. Second, and more fundamental: govulncheck detects known vulnerabilities, not malicious packages. None of the 61 PolinRider Go modules would trigger it before someone files a report. Layered defense is not optional: go.sum handles integrity, govulncheck handles known CVEs, code review handles logic — and none of them catch a malicious version in the hours after publication.
Deux limites comptent. Premièrement, l'analyse d'atteignabilité est conservatrice — elle peut signaler une vulnérabilité comme atteignable alors qu'elle ne l'est pas, et selon les recommandations de Go elle-même, elle doit être traitée comme un premier filtre puissant, pas une réponse complète. Deuxièmement, et plus fondamental : govulncheck détecte les vulnérabilités connues, pas les packages malveillants. Aucun des 61 modules Go PolinRider ne le déclencherait avant qu'un rapport soit déposé. La défense en couches n'est pas optionnelle : go.sum gère l'intégrité, govulncheck les CVE connues, la revue de code la logique — et aucun des trois n'attrape une version malveillante dans les heures suivant sa publication.
Hardening Checklist for Go Teams in 2026
Checklist de Durcissement pour les Équipes Go en 2026
Here is the practical checklist we recommend for every Go codebase, from solo projects to enterprise monorepos:
Voici la checklist pratique que nous recommandons pour chaque base de code Go, du projet solo au monorepo d'entreprise :
- Verify import paths character by character. Before adding a dependency, confirm the exact namespace against the project's official documentation — not against pkg.go.dev search results.
boltdb-go/boltvsboltdb/boltis one hyphen. - Vérifiez les chemins d'import caractère par caractère. Avant d'ajouter une dépendance, confirmez le namespace exact via la documentation officielle du projet — pas via les résultats de recherche pkg.go.dev.
boltdb-go/boltvsboltdb/bolt, c'est un tiret. - Commit go.sum and run
go mod verifyin CI. Never add checksum bypasses (GONOSUMDB=*,GOFLAGS=-insecure) to fix a pipeline. ScopeGOPRIVATEto internal domains only. - Committez go.sum et lancez
go mod verifyen CI. N'ajoutez jamais de bypass de checksums (GONOSUMDB=*,GOFLAGS=-insecure) pour réparer un pipeline. LimitezGOPRIVATEaux domaines internes. - Gate merges on govulncheck. Its reachability analysis is low-noise enough to block PRs without alert fatigue.
- Conditionnez les merges à govulncheck. Son analyse d'atteignabilité est assez peu bruyante pour bloquer des PRs sans fatigue d'alerte.
- Add a dependency age gate. Community tools like gomod-age refuse dependencies younger than N days — the Go equivalent of pnpm's
minimumReleaseAge, cutting exposure to freshly published malicious versions. - Ajoutez une barrière d'âge des dépendances. Des outils communautaires comme gomod-age refusent les dépendances de moins de N jours — l'équivalent Go du
minimumReleaseAgede pnpm, réduisant l'exposition aux versions malveillantes fraîchement publiées. - Review go.mod/go.sum diffs like code. A new indirect dependency, a replaced module path or an unexplained version bump deserves the same scrutiny as application logic. PolinRider hid payloads in config files precisely because nobody reviews them.
- Relisez les diffs go.mod/go.sum comme du code. Une nouvelle dépendance indirecte, un chemin de module remplacé ou un bump de version inexpliqué mérite le même examen que la logique applicative. PolinRider cachait ses payloads dans des fichiers de config précisément parce que personne ne les relit.
- Audit developer tooling execution paths. PolinRider payloads fired through VS Code tasks on folder open. Disable automatic task execution (
task.allowAutomaticTasks: off) and treat cloned repos as untrusted until reviewed. - Auditez les chemins d'exécution de l'outillage développeur. Les payloads PolinRider se déclenchaient via les tâches VS Code à l'ouverture du dossier. Désactivez l'exécution automatique des tâches (
task.allowAutomaticTasks: off) et traitez les dépôts clonés comme non fiables avant revue. - Monitor your go.sum continuously for new advisories. The gap between a malicious module's publication and its appearance in vulnerability databases is where most damage happens — continuous monitoring shortens your reaction time from weeks to hours.
- Surveillez votre go.sum en continu pour les nouveaux avis. L'écart entre la publication d'un module malveillant et son apparition dans les bases de vulnérabilités est là où les dégâts se produisent — la surveillance continue réduit votre temps de réaction de semaines à heures.
Frequently Asked Questions
Questions Fréquentes
Is the Go ecosystem safer than npm against supply chain attacks?
L'écosystème Go est-il plus sûr que npm contre les attaques supply chain ?
Partially. Go has no install scripts, an immutable module proxy and a cryptographic checksum database (sum.golang.org) — strong defenses against tampering that npm only approximated in 2026. But Go's decentralized model means no central publish gate, no registry-level 2FA and no malware scanning: PolinRider's 61 Go modules (vs 19 npm packages) show attackers now see Go as the softer target for first-publication malware.
Partiellement. Go n'a pas de scripts d'installation, dispose d'un module proxy immuable et d'une base de checksums cryptographique (sum.golang.org) — des défenses solides contre la falsification que npm n'a approchées qu'en 2026. Mais le modèle décentralisé de Go signifie aucune barrière de publication centrale, pas de 2FA au niveau registre ni de scan antimalware : les 61 modules Go de PolinRider (contre 19 packages npm) montrent que les attaquants voient désormais Go comme la cible la plus tendre pour les malwares publiés d'emblée malveillants.
What was the PolinRider campaign?
Qu'était la campagne PolinRider ?
PolinRider is a North Korea–linked supply chain campaign (Contagious Interview / Famous Chollima cluster) disclosed by Socket in July 2026. It published 162 malicious release artifacts across 108 unique packages: 61 Go modules, 19 npm libraries, 10 Composer packages and a Chrome extension, delivering the DEV#POPPER RAT and OmniStealer via blockchain RPC infrastructure, with the goal of persisting inside enterprise CI/CD pipelines.
PolinRider est une campagne supply chain liée à la Corée du Nord (cluster Contagious Interview / Famous Chollima) divulguée par Socket en juillet 2026. Elle a publié 162 artefacts malveillants couvrant 108 packages uniques : 61 modules Go, 19 bibliothèques npm, 10 packages Composer et une extension Chrome, délivrant le RAT DEV#POPPER et OmniStealer via des infrastructures RPC blockchain, avec pour objectif de persister dans les pipelines CI/CD d'entreprise.
Does go.sum protect me against malicious packages?
go.sum me protège-t-il contre les packages malveillants ?
No — go.sum and the checksum database guarantee integrity, not trust. They ensure the module you download is byte-identical to what everyone else downloads, which blocks tampering and silent republication. But if a module was malicious from its first publication, go.sum faithfully delivers the malware unaltered. You still need import path vigilance, dependency review and continuous vulnerability monitoring.
Non — go.sum et la base de checksums garantissent l'intégrité, pas la confiance. Ils assurent que le module téléchargé est identique à l'octet près à ce que tout le monde télécharge, ce qui bloque la falsification et la republication silencieuse. Mais si un module était malveillant dès sa première publication, go.sum délivre fidèlement le malware non altéré. La vigilance sur les chemins d'import, la revue des dépendances et la surveillance continue restent nécessaires.
How did the boltdb-go backdoor survive for three years?
Comment la backdoor boltdb-go a-t-elle survécu trois ans ?
The malicious typosquat was published in November 2021 and cached by the Go Module Proxy. The attackers then rewrote the Git tag on GitHub to point at clean code — so source audits saw nothing, while go get kept serving the cached backdoored version from proxy.golang.org. Socket discovered it in February 2025, over three years later.
Le typosquat malveillant a été publié en novembre 2021 et mis en cache par le Go Module Proxy. Les attaquants ont ensuite réécrit le tag Git sur GitHub pour pointer vers du code propre — les audits du code source ne voyaient donc rien, tandis que go get continuait de servir la version backdoorée en cache depuis proxy.golang.org. Socket l'a découverte en février 2025, plus de trois ans après.
Should I run govulncheck or a general SCA scanner for my Go projects?
Dois-je utiliser govulncheck ou un scanner SCA généraliste pour mes projets Go ?
Both, ideally. govulncheck's call-graph reachability analysis gives you a near-zero-false-positive CI gate for known Go vulnerabilities. A continuous monitoring layer on top of your go.sum catches new advisories published after your last build — which is exactly when supply chain incidents like PolinRider get reported.
Les deux, idéalement. L'analyse d'atteignabilité de govulncheck vous donne une gate CI quasi sans faux positifs pour les vulnérabilités Go connues. Une couche de surveillance continue sur votre go.sum attrape les nouveaux avis publiés après votre dernier build — ce qui est exactement le moment où les incidents supply chain comme PolinRider sont signalés.
Monitor your go.sum automatically
Surveillez votre go.sum automatiquement
CVE OptiBot scans your lockfiles daily — including go.sum — against the OSV.dev database and alerts you the moment a new vulnerability or malicious package advisory affects your dependencies. No code access required.
CVE OptiBot scanne vos lockfiles chaque jour — y compris go.sum — contre la base OSV.dev et vous alerte dès qu'une nouvelle vulnérabilité ou un avis de package malveillant touche vos dépendances. Aucun accès à votre code requis.
Start free monitoring Démarrer le monitoring gratuit