Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

SCA : analyser les vulnérabilités des dépendances

Par mis à jour le

Améliorer cette page

La SCA (Software Composition Analysis) inventorie les bibliothèques tierces que votre application embarque, puis les confronte aux vulnérabilités publiées. Elle couvre le code que vous n'avez pas écrit, souvent le plus volumineux de votre livraison. Cette leçon s'adresse à un développeur ou un DevOps qui veut savoir ce qu'un scanner SCA lit, comment lire son rapport, et comment le placer dans un pipeline sans le transformer en alarme permanente. Les exemples sont relevés avec Trivy 0.74.0 et Grype 0.119.0 sur un vrai projet npm.

  • Comprendre ce qu'un scanner SCA lit et à quelles bases il compare l'inventaire
  • Distinguer dépendances directes et transitives à partir d'un lockfile
  • Interpréter un rapport réel et en tirer la bonne correction
  • Bloquer un build sur les vulnérabilités graves, et seulement elles
  • Encadrer une exception par une justification et une date d'expiration
  • Rattacher ce contrôle à l'exigence SOCLE-APP-AST-3 du référentiel SOCLE

La SCA répond à une question simple : « quelles bibliothèques externes mon application embarque-t-elle, et lesquelles portent une faille connue ? ». Elle ne lit pas votre code comme le fait le SAST : elle lit la liste des composants, avec leurs versions exactes, et la compare aux bases de vulnérabilités. La fuite d'Equifax en 2017 en est le cas d'école : une version connue vulnérable d'Apache Struts, une dépendance non mise à jour, qu'un scanner SCA aurait signalée.

AspectSASTSCA
CibleCode écrit par l'équipeCode des dépendances
MéthodeMotifs et flux de données dans le codeVersions confrontées aux bases de vulnérabilités
TrouveFailles introduites par vos développeursFailles héritées des bibliothèques
ExempleInjection SQL dans votre routelodash 4.17.20, CVE-2021-23337

Deux mouvements se combinent. Une application tire beaucoup plus de composants qu'elle n'en déclare : mesuré sur le projet de test, 2 dépendances directes (express et lodash) produisent un lockfile de 51 paquets. Et les vulnérabilités sont publiées en continu : un composant sain le jour de la livraison peut porter une CVE le mois suivant, sans qu'une ligne de votre code ait changé. Sans inventaire automatisé, personne ne peut suivre ce rythme à la main.

Une CVE (Common Vulnerabilities and Exposures) est l'identifiant public d'une faille, et son score CVSS en estime la gravité. La leçon CVE, CVSS et EPSS explique comment les lire et les prioriser.

Un scanner SCA ne télécharge pas le code de vos dépendances pour l'analyser : il travaille sur leur inventaire. C'est ce qui le rend rapide, et c'est aussi ce qui le rend dépendant de la qualité de cet inventaire, d'où l'importance du lockfile.

  1. Extraction de l'inventaire : le scanner lit les fichiers de dépendances, de préférence les lockfiles, qui figent les versions exactes : package-lock.json, poetry.lock, go.sum, Cargo.lock. Un simple requirements.txt sans versions figées ne dit pas ce qui sera réellement installé.

  2. Arbre des dépendances : le lockfile contient aussi les dépendances transitives, celles de vos dépendances, avec leurs versions.

  3. Comparaison aux bases : chaque couple (paquet, version) est confronté aux bases publiques, comme la NVD du NIST, la GitHub Advisory Database ou OSV, qui agrège les avis de nombreux écosystèmes.

  4. Rapport : pour chaque correspondance, l'identifiant (CVE ou GHSA), la sévérité, la version installée et la version corrigée quand elle existe.

Le projet de test déclare deux dépendances figées dans son package.json, puis npm install --package-lock-only produit le lockfile complet. Les deux scanners lisent ce lockfile.

package.json
{
"name": "demo-sca",
"version": "1.0.0",
"private": true,
"dependencies": {
"express": "4.17.1",
"lodash": "4.17.20"
}
}
Fenêtre de terminal
IMG="aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969"
docker run --rm -v "$PWD:/src" -w /src "$IMG" fs --scanners vuln .

Trivy remonte 19 vulnérabilités : 7 HIGH, 6 MEDIUM, 6 LOW, aucune CRITICAL. Grype, sur le même lockfile, en trouve 19 également, avec la même répartition. Voici les lignes de lodash, extraites du tableau de Trivy :

Total: 19 (UNKNOWN: 0, LOW: 6, MEDIUM: 6, HIGH: 7, CRITICAL: 0)
│ lodash │ CVE-2021-23337 │ HIGH │ 4.17.20 │ 4.17.21 │ nodejs-lodash: command injection via template │
│ │ CVE-2026-4800 │ │ │ 4.18.0 │ lodash: lodash: Arbitrary code execution via untrusted input │
│ │ CVE-2020-28500 │ MEDIUM │ │ 4.17.21 │ nodejs-lodash: ReDoS via the toNumber, trim and trimEnd │
│ │ CVE-2025-13465 │ │ │ 4.17.23 │ lodash: prototype pollution in _.unset and _.omit functions │

Trois enseignements se lisent dans ces quatre lignes. D'abord, la nature exacte de la faille compte : CVE-2021-23337 est une injection de commande via _.template, pas une pollution de prototype, et son exploitation suppose que votre code passe une entrée externe à cette fonction. Ensuite, une même bibliothèque porte souvent plusieurs vulnérabilités corrigées dans des versions différentes : passer à 4.17.21 ne suffit pas, la colonne de droite mène à 4.18.0. Enfin, le tableau fusionne les cellules identiques : une case de sévérité vide reprend celle de la ligne du dessus, et CVE-2026-4800 est donc HIGH, pas sans sévérité.

Une dépendance directe est déclarée dans votre package.json. Une dépendance transitive est tirée par l'une d'elles. Sur le projet de test, 12 des 19 vulnérabilités se trouvent dans des transitives, comme qs, send ou path-to-regexp, que personne n'a choisies. Le lockfile dit qui les tire : qs 6.7.0 est demandé à la fois par express et par body-parser.

demo-sca
├── express 4.17.1 (directe)
│ ├── body-parser (transitive)
│ │ └── qs 6.7.0 (transitive)
│ ├── qs 6.7.0 (transitive)
│ └── send (transitive)
└── lodash 4.17.20 (directe)

La conséquence est pratique : on ne corrige presque jamais une transitive en l'ajoutant à la main. On monte la dépendance directe qui la tire, ici express, ou on force la version avec le mécanisme du gestionnaire de paquets (overrides pour npm), en le documentant.

Le scan SCA a sa place à trois moments : sur le poste avant de pousser, à chaque merge request pour bloquer, et en surveillance continue pour ce qui est déjà livré. Le piège est le même qu'en SAST : sans option dédiée, les deux scanners sortent en code 0 quoi qu'ils trouvent. Mesuré : Trivy sans --exit-code sort en 0 malgré 19 vulnérabilités, Grype sans --fail-on aussi.

Fenêtre de terminal
# Sur le poste
trivy fs --scanners vuln .
grype dir:.

Le job utilise l'image officielle de Trivy, épinglée par digest, plutôt qu'une action tierce : moins de code auquel faire confiance dans le pipeline. permissions: {} retire tous les droits par défaut, contents: read suffit pour cloner.

.github/workflows/sca.yml
name: SCA
on:
pull_request:
permissions: {}
jobs:
trivy:
runs-on: ubuntu-24.04
permissions:
contents: read
container:
image: aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Trivy, échec sur HIGH et CRITICAL
run: trivy fs --scanners vuln --severity CRITICAL,HIGH --exit-code 1 .

L'image de Trivy a pour point d'entrée le binaire trivy lui-même : sur GitLab, entrypoint: [""] le neutralise pour que le script du job s'exécute dans un shell. Sur GitHub Actions, un job container: lance ses étapes dans un shell du conteneur, sans ce réglage.

La SCA s'applique aussi aux images : elles embarquent les dépendances de l'application et les paquets du système de base. La commande change de cible, trivy image ou grype suivi du nom de l'image, et l'image scannée se désigne par digest, sinon le rapport ne dit pas quelle image il a lue. Le scan d'image est détaillé dans la leçon Trivy du module conteneurs.

Un scan en CI ne voit que ce qui passe dans le pipeline. Une image déployée il y a six mois ne repasse pas en CI, alors que de nouvelles CVE la concernent peut-être. La réponse est un inventaire conservé, le SBOM, qu'un outil comme Dependency-Track réexamine à chaque publication de vulnérabilité. Le SBOM a sa propre leçon dans le module supply chain.

Bloquer sur toutes les vulnérabilités paralyse les équipes, ne bloquer sur aucune revient à ne pas scanner. Une politique raisonnable bloque les sévérités CRITICAL et HIGH, ouvre un ticket pour les MEDIUM, et passe les LOW en revue. L'option --ignore-unfixed de Trivy écarte les vulnérabilités sans version corrigée, pour ne pas bloquer sur ce qu'on ne peut pas réparer ; sur le projet de test, elle ne retire rien, car les 19 vulnérabilités ont toutes un correctif publié.

SévéritéActionDélai indicatif
CRITICALBloquer le buildCorrection immédiate
HIGHBloquer le buildCorrection avant la fusion
MEDIUMTicket avec échéanceSprint suivant
LOWRevue périodiqueSelon le contexte

Certaines vulnérabilités ne s'appliquent pas à votre usage : la fonction vulnérable n'est jamais appelée, ou pas avec une entrée externe. L'exception est alors légitime, à condition d'être justifiée et datée. Trivy le permet nativement, avec deux fichiers dont le comportement diffère.

.trivyignore.yaml
vulnerabilities:
- id: CVE-2021-23337
statement: "_.template n'est jamais appelé avec une entrée externe ; revue le 2026-12-01"
expired_at: 2027-01-01
Fenêtre de terminal
trivy fs --scanners vuln --ignorefile .trivyignore.yaml .

Mesuré : avec cette exception, le rapport passe de 19 à 18 vulnérabilités ; avec une date expired_at dépassée, la CVE réapparaît d'elle-même. Piège à connaître : le format YAML n'est lu qu'avec --ignorefile, alors que l'ancien format texte, .trivyignore, est lu par défaut. Un .trivyignore.yaml posé sans l'option n'a aucun effet, et l'équipe croit à tort son exception active.

La meilleure exception reste celle qu'on n'a pas besoin d'écrire. Des outils comme Dependabot ou Renovate ouvrent des merge requests de mise à jour, une par dépendance ou par groupe, que la CI valide avant fusion. Ne négligez pas les dépendances de développement : un outil de test ou de build compromis s'exécute dans le pipeline, avec ses secrets.

Trivy et Grype, les deux scanners mesurés ici, sont libres et tournent en local ; ils couvrent l'essentiel des besoins d'une équipe. Les autres outils répondent à des besoins différents : une plateforme de suivi dans le temps, ou un service commercial avec correction automatique.

OutilTypePoint fortCas d'usage
TrivyCLI, libreUn binaire pour dépendances, images et IaCScan CI universel
GrypeCLI, libreCouplé à Syft pour les SBOMScan d'images et de SBOM
OSV-ScannerCLI, libreBase OSV, très large couvertureProjets multi-écosystèmes
Dependency-TrackPlateforme, libreSuivi continu à partir des SBOMGouvernance d'un parc
SnykSaaS, commercialIntégrations, correctifs proposésÉquipes avec budget

La SCA ne voit que ce qui est publié : une faille non encore divulguée, une 0-day, lui échappe par construction. Elle signale une vulnérabilité présente dans une version, pas une vulnérabilité atteignable par votre code : une CVE dans une fonction jamais appelée reste dans le rapport. Elle dépend aussi de l'inventaire : sans lockfile, ou avec un binaire copié à la main dans le dépôt, elle rate des composants. Elle complète donc le SAST et le DAST, elle ne les remplace pas.

  1. La SCA confronte l'inventaire de vos dépendances aux vulnérabilités publiées ; elle ne lit pas votre code.
  2. Le lockfile est la source de vérité : 2 dépendances directes tiraient 51 paquets.
  3. La majorité des vulnérabilités du projet de test, 12 sur 19, étaient dans des transitives.
  4. On corrige une transitive en montant la dépendance directe qui la tire.
  5. Sans --exit-code (Trivy) ou --fail-on (Grype), le scan ne bloque rien.
  6. Une exception se justifie et expire : .trivyignore.yaml exige --ignorefile.
  7. La SCA ne voit ni les 0-day ni l'atteignabilité réelle d'une faille.
  8. Preuve attendue par SOCLE-APP-AST-3 : les constats SCA suivis dans le processus de gestion des vulnérabilités.

Vérifiez que l'essentiel de cette leçon est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn