Aller au contenu
Sécurité medium

Scanner les vulnérabilités de conteneurs avec Grype

15 min de lecture

logo grype

Grype détecte les vulnérabilités connues (CVE) dans vos images conteneurs et votre code source en quelques secondes. Une seule commande suffit pour scanner une image Alpine Python et obtenir la liste des CVE triées par sévérité, avec les scores EPSS (probabilité d’exploitation réelle) et RISK pour prioriser vos corrections. Ce guide vous montre comment installer Grype, scanner vos images, interpréter les résultats et intégrer le tout dans votre pipeline CI/CD.

  • Scanner une image conteneur : détecter les CVE avec scores EPSS et RISK
  • Scanner un répertoire source : identifier les dépendances vulnérables avant le build
  • Interpréter les résultats : comprendre sévérité, EPSS et colonnes de sortie
  • Bloquer les déploiements : utiliser --fail-on en CI/CD
  • Configurer Grype : fichier .grype.yaml, gestion de la DB, filtrage VEX

Vous utilisez Grype dès que vous manipulez des images conteneurs ou du code applicatif avec des dépendances tierces :

  • Vous construisez des images Docker et voulez vérifier qu’elles ne contiennent pas de CVE connues avant de les pousser en registre
  • Vous développez une application Python, Node ou Go et voulez détecter les dépendances vulnérables dans votre requirements.txt, package.json ou go.mod
  • Vous mettez en place un pipeline CI/CD et avez besoin d’un gate de sécurité qui bloque automatiquement les déploiements à risque
  • Vous gérez des images en production et voulez un scan régulier pour détecter les nouvelles CVE publiées
  • Vous travaillez avec des SBOM (générés par Syft) et voulez les analyser pour trouver les vulnérabilités

Dans l’écosystème de la sécurité applicative, Grype joue un rôle complémentaire avec d’autres outils :

  • Syft génère le SBOM (inventaire des composants)
  • Grype scanne ce SBOM pour détecter les CVE
  • VEX filtre les faux positifs selon votre contexte
Fenêtre de terminal
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
grype version
# Application: grype
# Version: 0.111.0
Fenêtre de terminal
brew tap anchore/grype
brew install grype
  • asdf-vm : asdf plugin add grype && asdf install grype latest
  • Docker : docker run --rm anchore/grype:latest <image>

Grype analyse deux types de sources :

  1. Images de conteneurs : scan de tous les packages installés (APK, DEB, RPM, binaires Go, dépendances Python/Node/Java…)
  2. Répertoires source : scan des fichiers de dépendances (requirements.txt, package.json, go.mod, pom.xml…)

Écosystèmes supportés :

  • Alpine (apk)
  • C (conan)
  • C++ (conan)
  • Dart (pubs)
  • Debian (dpkg)
  • Dotnet (deps.json)
  • Objective-C (cocoapods)
  • Go (go.mod, Go binaries)
  • Haskell (cabal, stack)
  • Java (jar, ear, war, par, sar)
  • JavaScript (npm, yarn)
  • Jenkins Plugins (jpi, hpi)
  • PHP (composer)
  • Python (wheel, egg, poetry, requirements.txt)
  • Red Hat (rpm)
  • Ruby (gem)
  • Rust (cargo.lock)
  • Swift (cocoapods)

Scan d’une image Docker pour identifier les CVE :

Fenêtre de terminal
grype python:3.12-alpine -o table -q
# NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
# python 3.12.13 *3.13.11, 3.14.1, 3.15.0 binary CVE-2025-13836 High 0.2% (41st) 0.1
# libcrypto3 3.5.5-r0 3.5.6-r0 apk CVE-2026-28389 High < 0.1% (18th) < 0.1
# libssl3 3.5.5-r0 3.5.6-r0 apk CVE-2026-28389 High < 0.1% (18th) < 0.1
# requests 2.31.0 2.32.4 python GHSA-9hjg-9r4m Medium 0.2% (43rd) 0.1
# ... (22 vulnérabilités)

Détail du processus :

  1. Chargement : Grype extrait les métadonnées de l’image (layers, packages)
  2. Inventaire : Il identifie tous les packages : APK Alpine (musl, libssl), Python (flask, requests), binaires compilés
  3. Comparaison : Chaque package est comparé à la base de vulnérabilités (NVD, GitHub Advisory, Alpine Security)
  4. Scoring : Les CVE sont enrichies avec scores CVSS (gravité), EPSS (probabilité d’exploitation) et RISK (score combiné)
  5. Affichage : Résultats triés par sévérité avec percentile EPSS

Colonnes de sortie :

ColonneSignification
NAMEPackage vulnérable
INSTALLEDVersion installée
FIXED INVersion corrigée (vide si pas de fix)
VULNERABILITYIdentifiant CVE ou GHSA
SEVERITYNiveau CVSS : Critical, High, Medium, Low
EPSSProbabilité d’exploitation réelle + percentile
RISKScore de risque combiné (sévérité × exploitabilité)

Le score EPSS indique le percentile : “41st” signifie que 41% des CVE connues sont moins exploitées que celle-ci. Le score RISK combine la sévérité CVSS et l’EPSS pour donner une priorité actionnable.

Scan du code source (avant construction de l’image) :

Fenêtre de terminal
grype dir:. -o table -q
# NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
# jinja2 3.1.2 3.1.4 python GHSA-h75v-3vvj-5mfj Medium 0.8% (74th) 0.4
# requests 2.31.0 2.32.4 python GHSA-9hjg-9r4m-mvj7 Medium 0.2% (43rd) 0.1
# flask 3.0.0 3.1.3 python GHSA-68rp-wp8r-4726 Low < 0.1% (1st) < 0.1
# ... (9 vulnérabilités)

Différence image vs source :

  • Image : 12 CVE (packages système Alpine + Python)
  • Source : 4 CVE (uniquement dépendances Python)

Pourquoi scanner le source ? Détecter les CVE Python avant le build Docker, dans votre IDE ou pre-commit Git.

Grype prend en argument les sources suivantes :

Fenêtre de terminal
grype podman:yourrepo/yourimage@sha256:... Podman daemon
grype docker:yourrepo/yourimage@sha256:... Docker daemon
grype docker-archive:path/to/image.tar tarball Docker
grype oci-archive:path/to/image.tar tarball OCI
grype oci-dir:path/to/yourimage OCI layout directory
grype singularity:path/to/yourimage.sif Singularity Image Format
grype dir:path/to/yourproject répertoire source
grype sbom:path/to/syft.json fichier SBOM
grype registry:yourrepo/yourimage@sha256:... registre distant
grype purl:path/to/purl/file fichier PURL

La commande explain approfondit la compréhension d’une CVE spécifique :

Fenêtre de terminal
grype alpine:latest -o json -q | grype explain --id CVE-2026-28389

Sortie (condensée) :

CVE-2026-28389 from nvd:cpe (High)
Issue summary: During processing of a crafted CMS EnvelopedData message
with KeyAgreeRecipientInfo a NULL pointer dereference can happen.
Matched packages:
- Package: libcrypto3, version: 3.5.5-r0
Fix versions: 3.5.6-r0
- Package: libssl3, version: 3.5.5-r0
Fix versions: 3.5.6-r0
URLs:
- https://nvd.nist.gov/vuln/detail/CVE-2026-28389

Informations clés :

  • Package vulnérable : libcrypto3 et libssl3 (OpenSSL)
  • Sévérité : High
  • Type : NULL pointer dereference (déni de service)
  • Correction : Mettre à jour Alpine pour obtenir OpenSSL 3.5.6

Grype produit plusieurs formats selon votre usage :

Pour l’humain :

  • table (défaut) : Tableau lisible avec colonnes NAME, INSTALLED, VULNERABILITY, SEVERITY, EPSS

Pour l’automatisation :

  • json : Toutes les métadonnées CVE (description, CVSS, EPSS, URLs, fix disponible, chemins de fichiers)
  • cyclonedx / cyclonedx-json : Standard CycloneDX 1.4 pour intégration Dependency Track

Pour la personnalisation :

  • template : Template Go personnalisé (exemple : générer un rapport Markdown)

Exemple JSON pour automatisation :

Fenêtre de terminal
grype alpine:latest -o json -q > vulnerabilities.json
jq '{total: (.matches | length), high: [.matches[] | select(.vulnerability.severity == "High")] | length, medium: [.matches[] | select(.vulnerability.severity == "Medium")] | length}' vulnerabilities.json
# {"total": 22, "high": 12, "medium": 6}

Le format JSON est essentiel pour :

  • Filtrer les CVE avec jq ou scripts Python
  • Stocker les résultats historiques
  • Intégrer avec des plateformes comme Dependency Track

Option --fail-on pour faire échouer le pipeline CI/CD si des vulnérabilités dépassent un seuil de sévérité :

Fenêtre de terminal
grype python:3.12-alpine --fail-on high -q
# NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
# python 3.12.13 *3.13.11, 3.14.1, 3.15.0 binary CVE-2025-13836 High 0.2% (41st) 0.1
# libcrypto3 3.5.5-r0 3.5.6-r0 apk CVE-2026-28389 High < 0.1% (18th) < 0.1
# ...
# 1 error occurred:
# * discovered vulnerabilities at or above the severity threshold

Résultat : code retour 1 (échec). Utile en CI/CD pour bloquer un déploiement contenant des CVE de sévérité haute ou critique.

Grype se configure via un fichier .grype.yaml pour personnaliser le comportement du scanner selon vos besoins. C’est utile pour standardiser les scans dans une équipe ou un projet.

Principaux réglages :

# Format de sortie par défaut
output: table # ou json, cyclonedx-json
# Échouer selon sévérité (utile en CI/CD)
fail-on-severity: high # options: negligible, low, medium, high, critical
# Filtrer uniquement les CVE corrigées (ignorer les not-fixed)
only-fixed: false
# Scope du scan pour les images
search:
scope: squashed # analyse l'image finale compressée
# scope: all-layers # analyse toutes les layers (plus lent, plus exhaustif)
# Base de données de vulnérabilités
db:
auto-update: true # mise à jour auto au lancement
cache-dir: ~/.cache/grype/db
max-allowed-built-age: 120h # alerte si DB > 5 jours
# Intégration VEX pour filtrer les faux positifs
vex-documents:
- ./vex/devops-status-api.vex.json
- ./vex/global.vex.json
# Ignorer certains chemins (exemple : tests, vendor)
exclude:
- "**/test/**"
- "**/vendor/**"

Chemins de recherche (ordre de priorité) :

  1. .grype.yaml (racine du projet)
  2. .grype/config.yaml
  3. ~/.grype.yaml (configuration utilisateur)
  4. ~/.config/grype/config.yaml

Exemple d’usage : créer .grype.yaml à la racine de votre projet pour que tous les développeurs utilisent les mêmes seuils de sévérité et les mêmes documents VEX.

La base de vulnérabilités de Grype est cruciale : elle contient toutes les CVE connues provenant de NVD, GitHub Advisory Database, Alpine Security, etc. Elle est mise à jour quotidiennement par Anchore.

Vérifier l’état de la base :

/home/user/.cache/grype/db/6/vulnerability.db
grype db status
# Schema: v6.1.4
# Built: 2026-04-14T06:52:37Z
# From: https://grype.anchore.io/databases/v6/...
# Status: valid

Informations clés :

  • Schema : Version du format DB (v6 depuis Grype 0.105+)
  • Built : Date de génération (vérifiez qu’elle est récente)
  • Status : valid si tout est OK

Mise à jour manuelle :

Fenêtre de terminal
grype db update
# ✔ Vulnerability DB [no update available]

Par défaut, Grype met à jour la DB automatiquement au lancement si elle date de plus de 24h. Pour forcer une vérification :

Fenêtre de terminal
grype db update --force

En CI/CD : la mise à jour auto peut ralentir les builds. Deux stratégies :

  1. Cache avec expiration : cache la DB pendant 7 jours, puis régénère
  2. Mise à jour manuelle : grype db update dans un job séparé quotidien

Taille de la DB : environ 200-300 Mo compressée, 1-2 Go décompressée. Elle est stockée dans ~/.cache/grype/db/.

Intégrer Grype dans votre pipeline automatise la détection des vulnérabilités avant le déploiement en production. L’objectif : détecter tôt, corriger vite.

Exemple GitHub Actions :

- name: Build and get digest
run: |
docker build -t myapp .
echo "DIGEST=$(docker inspect myapp --format='{{.Id}}')" >> $GITHUB_ENV
- name: Scan image
run: |
grype myapp@${{ env.DIGEST }} \
--fail-on critical \
-o json > grype-report.json
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: grype-report
path: grype-report.json

Stratégie de seuil :

  • --fail-on critical : Bloque uniquement les CVE critiques (CVSS ≥ 9.0)
  • --fail-on high : Bloque critical + high (CVSS ≥ 7.0)
  • --fail-on medium : Plus strict, peut générer beaucoup de faux positifs

Workflow recommandé :

  1. Scan de répertoire (grype dir:.) lors du commit (pré-commit hook)
  2. Scan d’image lors du build CI/CD
  3. Fail-on critical pour bloquer les déploiements à risque
  4. Upload JSON pour traçabilité et analyse historique
  5. Intégration VEX pour filtrer les faux positifs validés

Optimisation cache :

- name: Cache Grype DB
uses: actions/cache@v4
with:
path: ~/.cache/grype
key: grype-db-${{ hashFiles('**/Dockerfile') }}
restore-keys: grype-db-

:::caution Fraîcheur de la DB

La base CVE de Grype est mise à jour quotidiennement. En CI/CD avec cache, régénérez le cache hebdomadairement pour détecter les nouvelles CVE. Sinon, vous risquez de manquer des vulnérabilités récemment publiées.

:::

SymptômeCause probableSolution
the vulnerability database was built X weeks agoDB trop anciennegrype db update
Aucune CVE détectée sur une image connue comme vulnérableDB pas à jour ou scope trop restreintgrype db update --force puis rescanner avec --scope all-layers
unsupported database schema après mise à jourIncompatibilité schema DBgrype db delete puis grype db update
Scan très lent (> 30s)Analyse all-layers sur image volumineusePasser en scope: squashed dans .grype.yaml
explain ne montre rienCommande prototype, ID non trouvéVérifier l’ID exact dans la sortie JSON
  • Grype scanne images conteneurs, répertoires source et SBOM en quelques secondes
  • Les colonnes EPSS et RISK permettent de prioriser les corrections selon le risque réel d’exploitation, pas seulement la sévérité CVSS
  • --fail-on intégré en CI/CD bloque automatiquement les déploiements contenant des CVE au-dessus d’un seuil
  • La base de vulnérabilités se met à jour automatiquement toutes les 24h — en CI/CD, gérez le cache avec une expiration hebdomadaire
  • Grype + Syft + VEX forment une chaîne complète : inventaire → détection → filtrage des faux positifs

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn