
Une seule dépendance vulnérable dans votre go.mod peut exposer tout le binaire ; encore faut-il la détecter, la corriger et prouver ce que vous livrez. Ce guide vous apprend à scanner votre code avec govulncheck, qui ne signale que les failles réellement atteignables, à maîtriser l'intégrité des dépendances via go.mod, go.sum et go mod verify, à produire un SBOM (l'inventaire de ce que contient votre binaire), et à câbler ces contrôles en intégration continue pour bloquer une livraison vulnérable. Public visé : vous savez compiler un binaire Go et gérer un module. Exemples testés sur Go 1.26.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Détecter les vulnérabilités atteignables avec
govulncheck. - Vérifier l'intégrité des dépendances avec
go.sumetgo mod verify. - Générer un SBOM du binaire, natif ou au format CycloneDX.
- Bloquer une livraison vulnérable en intégration continue.
Détecter les vulnérabilités avec govulncheck
Section intitulée « Détecter les vulnérabilités avec govulncheck »govulncheck est l'outil officiel de l'équipe Go. Sa force par rapport à un scanner classique : il ne se contente pas de lire les versions du go.mod, il fait une analyse d'atteignabilité (call graph). Il ne remonte donc que les vulnérabilités dont le code vulnérable est effectivement appelé par le vôtre, ce qui réduit drastiquement le bruit. Installez-le puis lancez-le sur le projet :
go install golang.org/x/vuln/cmd/govulncheck@latestgovulncheck ./...Sur un projet qui utilise une vieille version de golang.org/x/text et appelle language.ParseAcceptLanguage, le rapport est précis : il nomme la faille, la version qui corrige, et la trace d'appel exacte qui prouve l'atteignabilité :
Vulnerability #1: GO-2022-1059 Denial of service via crafted Accept-Language header in golang.org/x/text/language More info: https://pkg.go.dev/vuln/GO-2022-1059 Found in: golang.org/x/text@v0.3.5 Fixed in: golang.org/x/text@v0.3.8 Example traces found: #1: main.go:11:44: main.main calls language.ParseAcceptLanguageYour code is affected by 2 vulnerabilities from 1 module.La correction consiste presque toujours à monter la dépendance vers la version corrigée, puis à relancer le scan :
go get golang.org/x/text@latestgo mod tidygovulncheck ./...No vulnerabilities found.Importé n'est pas appelé
Section intitulée « Importé n'est pas appelé »C'est la nuance qui distingue govulncheck d'un scanner classique. Reprenez le même projet avec sa dépendance vulnérable en version 0.3.5, mais sans appeler la fonction fautive : on se contente de language.Make, qui n'est concernée par aucune des deux failles.
tag := language.Make("fr") // fonction NON vulnérableLe verdict s'inverse complètement :
No vulnerabilities found.Your code is affected by 0 vulnerabilities.... but your code doesn't appear to call these vulnerabilities.La dépendance vulnérable est toujours là, et govulncheck le sait. Mais comme aucun chemin d'appel n'atteint le code fautif, il ne déclenche pas d'alerte. Un scanner qui lirait seulement le go.mod vous aurait noyé sous deux alertes sans objet. C'est tout l'intérêt de l'atteignabilité : moins de bruit, des alertes qui comptent.
Scanner un binaire déjà compilé
Section intitulée « Scanner un binaire déjà compilé »On n'a pas toujours la source sous la main : un artefact issu d'une chaîne de build, un binaire tiers. govulncheck analyse aussi un binaire compilé avec -mode binary :
go build -o outil .govulncheck -mode binary outilSur un binaire qui appelle réellement la fonction vulnérable, les failles ressortent :
Vulnerability #1: GO-2022-1059 Found in: golang.org/x/text@v0.3.5 Fixed in: golang.org/x/text@v0.3.8Un binaire ne contient toutefois pas le graphe d'appels détaillé : le mode binaire ne montre pas la trace menant à la faille et se révèle un peu moins précis. Réservez-le à la vérification d'un artefact livré ; préférez le scan de la source quand vous l'avez.
Maîtriser go.mod et go.sum
Section intitulée « Maîtriser go.mod et go.sum »Le fichier go.mod déclare vos dépendances et leurs versions ; le fichier go.sum enregistre les empreintes cryptographiques (hachages) de chaque module téléchargé. Ce second fichier est votre garantie d'intégrité : il détecte toute altération d'une dépendance entre deux récupérations. Commitez toujours go.sum, et vérifiez à tout moment que le cache local correspond aux empreintes attendues :
go mod verifyall modules verifiedDeux réflexes complètent cette base. Épinglez des versions précises plutôt que de dépendre de @latest en production, pour des builds reproductibles. Et faites régulièrement le ménage avec go mod tidy, qui synchronise go.mod et go.sum avec les imports réels du code, en retirant les dépendances devenues inutiles.
Générer un SBOM du binaire
Section intitulée « Générer un SBOM du binaire »Un SBOM (Software Bill of Materials, la nomenclature logicielle) est l'inventaire de tout ce que contient votre binaire : c'est ce qui permet, quand une faille est publiée, de savoir en minutes si vous êtes concerné. Ne confondez pas avec go.sum : ce dernier prouve l'intégrité, le SBOM décrit le contenu.
Go fournit déjà un inventaire minimal, sans aucun outil externe : la commande go version -m liste les modules embarqués dans un binaire compilé, avec leur version et leur empreinte :
go build -o outil .go version -m outil mod example.com/scalab (devel) dep golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEeg...Pour un SBOM au format standard, échangeable avec d'autres outils de sécurité, utilisez cyclonedx-gomod, qui produit du CycloneDX avec les identifiants purl de chaque composant :
go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latestcyclonedx-gomod mod -json -output sbom.json .Le fichier obtenu déclare son format et liste chaque dépendance de façon interopérable :
bomFormat: CycloneDX specVersion: 1.6composant: golang.org/x/text v0.40.0 purl: pkg:golang/golang.org/x/text@v0.40.0Bloquer une livraison vulnérable en CI
Section intitulée « Bloquer une livraison vulnérable en CI »L'intérêt de ces contrôles se révèle en intégration continue : un scan qui échoue doit stopper la livraison avant qu'un binaire vulnérable ne parte en production. govulncheck est fait pour cela, car il renvoie un code de sortie non nul quand il trouve une faille atteignable. Sur notre projet, le code passe de 0 à 3 selon l'état :
govulncheck ./... ; echo "exit=$?"# projet corrigé -> exit=0# projet vulnérable -> exit=3Un job qui lance simplement govulncheck ./... échoue donc de lui-même dès qu'une faille apparaît. L'équipe Go publie aussi une action officielle, golang/govulncheck-action (à épingler par SHA comme toute action), pour l'intégrer sans script. Combinez ce garde-fou avec go mod verify et la génération du SBOM à chaque build, et vous couvrez les trois piliers : détecter les failles, garantir l'intégrité, inventorier le livré.
Erreurs fréquentes
Section intitulée « Erreurs fréquentes »La sécurité de la supply chain donne un faux sentiment de maîtrise quand on comprend mal les outils. Voici les confusions les plus courantes.
| Idée reçue | Réalité | Bon réflexe |
|---|---|---|
« govulncheck lit mon go.sum » | Il analyse le graphe d'appels, pas juste les versions | Écrire le code test réel ; il ne signale que l'atteignable |
| « Zéro alerte = zéro risque » | reflect et unsafe échappent à l'analyse | Défense en profondeur, ne pas s'arrêter à un seul outil |
« go.sum est mon SBOM » | go.sum prouve l'intégrité, pas le contenu | Générer un SBOM distinct (go version -m, CycloneDX) |
« Un scanner de go.mod suffit » | Il sur-rapporte des failles dans des dépendances non appelées | Préférer l'analyse d'atteignabilité de govulncheck |
« @latest me garde à jour » | Il casse la reproductibilité des builds | Épingler les versions, mettre à jour de façon contrôlée |
Le contresens le plus répandu oppose govulncheck aux scanners qui se contentent de lire le go.mod. Ces derniers signalent toute vulnérabilité présente dans l'arbre des dépendances, y compris dans une bibliothèque transitive que votre code n'appelle jamais. Vous vous retrouvez alors à trier des alertes sans objet. govulncheck élimine ce bruit en prouvant, trace d'appel à l'appui, qu'une faille est réellement joignable depuis votre programme. C'est précisément ce qui en fait un bon premier filtre, à condition de garder en tête ses angles morts (reflect, unsafe).
À retenir
Section intitulée « À retenir »govulncheckne signale que les vulnérabilités atteignables, avec la trace d'appel qui le prouve ; il ignorereflectetunsafe.- On corrige en montant la dépendance vers la version marquée
Fixed in, puis on relance le scan. go.sumgarantit l'intégrité des dépendances ;go mod verifyla vérifie,go mod tidyla nettoie.- Un SBOM décrit le contenu livré :
go version -men natif, CycloneDX (cyclonedx-gomod) pour un format standard. - En CI,
govulncheckrenvoie exit 3 sur une faille atteignable : le job échoue et bloque la livraison. go.sumn'est pas un SBOM : l'un prouve l'intégrité, l'autre inventorie les composants.