Aller au contenu
Sécurité medium

OSV-Scanner : détecter les dépendances vérolées

15 min de lecture

Dès que vous ajoutez une bibliothèque à un projet (une dépendance, comme lodash en JavaScript ou jinja2 en Python), vous faites tourner du code que vous n'avez pas écrit. Deux choses peuvent mal tourner : cette bibliothèque contient une faille de sécurité connue, ou bien c'est carrément un paquet piégé (un faux paquet qui imite un vrai pour voler vos mots de passe ou vos clés).

OSV-Scanner est un outil gratuit qui repère ces deux dangers. Il lit la liste précise des dépendances de votre projet et la compare à des bases publiques de menaces tenues à jour par la communauté. S'il trouve une dépendance dangereuse, il vous le dit — et peut bloquer la suite.

Ce guide s'adresse à un développeur ou un ingénieur DevSecOps qui veut repérer une dépendance dangereuse avant qu'elle ne s'installe. Vous installerez l'outil, scannerez un projet npm (JavaScript) et un projet Python géré par uv, puis mettrez la détection en place à trois moments : sur votre poste, au moment du commit (l'enregistrement de votre code dans Git), et dans la CI (les contrôles automatiques qui tournent à chaque modification).

  • Installer OSV-Scanner v2 et comprendre ce qu'il détecte.
  • Scanner un lockfile npm et un lockfile uv contre la base OSV.
  • Ajouter une dépendance en scannant avant d'installer quoi que ce soit.
  • Bloquer une dépendance vérolée au commit avec un hook pre-commit.
  • Brancher OSV-Scanner en CI GitHub Actions (scan de PR + scan planifié).
  • Positionner le scanner par rapport à un artifact firewall.

La « liste précise des dépendances » que lit l'outil, c'est le fichier de verrouillage (ou lockfile) : package-lock.json pour npm, uv.lock pour uv. Il fige la version exacte de chaque bibliothèque utilisée par votre projet, y compris celles tirées indirectement. OSV-Scanner le lit pour savoir quoi vérifier — il n'installe rien.

Pour comparer, OSV-Scanner s'appuie sur le format OSV (Open Source Vulnerability), une façon standard de décrire un problème de sécurité, commune à tous les langages. Deux familles d'identifiants vous concernent.

Les enregistrements CVE-/GHSA-/PYSEC- décrivent des vulnérabilités d'un paquet par ailleurs légitime — une faille à corriger en montant de version. Les enregistrements MAL- décrivent un paquet malveillant : typosquat, dependency confusion, ou version compromise d'un paquet populaire. C'est cette seconde famille, alimentée par le dépôt OpenSSF Malicious Packages, qui distingue OSV-Scanner d'un simple scanner de CVE.

OSV-Scanner est un binaire Go, distribué pour Linux, macOS et Windows. Choisissez une méthode selon votre poste.

Fenêtre de terminal
brew install osv-scanner

Vérifiez l'installation. La sortie doit afficher une version 2.x :

Fenêtre de terminal
osv-scanner --version
osv-scanner version: 2.3.8
osv-scalibr version: 0.4.5

Premier cas d'usage, le plus simple : vous avez déjà un projet et vous voulez savoir si ses dépendances actuelles sont saines. Le geste de base est osv-scanner scan -L <lockfile>. L'option -L cible un fichier de verrouillage précis ; OSV-Scanner reconnaît nativement package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, uv.lock, Pipfile.lock, go.sum et bien d'autres.

Sur un projet épinglant minimist@1.2.0 (une version réellement vulnérable) :

Fenêtre de terminal
osv-scanner scan -L package-lock.json
Total 1 package affected by 2 known vulnerabilities (1 Critical, 0 High, 1 Medium) from 1 ecosystem.
+-------------------------------------+------+-----------+----------+---------+---------------+
| OSV URL | CVSS | ECOSYSTEM | PACKAGE | VERSION | FIXED VERSION |
+-------------------------------------+------+-----------+----------+---------+---------------+
| https://osv.dev/GHSA-vh95-rmgr-6w4m | 5.6 | npm | minimist | 1.2.0 | 1.2.3 |
| https://osv.dev/GHSA-xvch-5gv4-984h | 9.8 | npm | minimist | 1.2.0 | 1.2.6 |
+-------------------------------------+------+-----------+----------+---------+---------------+

La colonne FIXED VERSION vous donne la cible de remédiation immédiate. Surtout, retenez le code de sortie : OSV-Scanner renvoie 1 dès qu'il trouve une vulnérabilité ou un paquet malveillant, 0 si tout est propre. C'est ce code qui fera échouer un hook ou un job CI.

Fenêtre de terminal
osv-scanner scan -L package-lock.json ; echo "code de sortie : $?"

Pour scanner tout un dépôt d'un coup (il découvre les lockfiles récursivement) :

Fenêtre de terminal
osv-scanner scan -r ./

Second cas d'usage : vous ajoutez une dépendance. Le réflexe npm install <paquet> télécharge et exécute les scripts du paquet — si le paquet est piégé, le mal est fait avant qu'un scanner intervienne. Le bon réflexe inverse l'ordre, en quatre temps :

  1. créer le fichier de verrouillage sans rien installer ;
  2. scanner ce fichier ;
  3. installer seulement si le scan est vert ;
  4. automatiser ce contrôle au moment du commit.

1. Créer le fichier de verrouillage sans rien installer

Section intitulée « 1. Créer le fichier de verrouillage sans rien installer »

npm et uv savent résoudre les versions et écrire le lockfile seul, sans télécharger ni exécuter le moindre paquet. C'est ce qui rend possible le scan avant l'installation.

L'option --package-lock-only met à jour package-lock.json sans créer node_modules ni exécuter de script :

Fenêtre de terminal
npm install lodash@4.17.4 --package-lock-only

C'est la commande de base vue plus haut, appliquée au lockfile fraîchement résolu — et aucun code du nouveau paquet n'a encore tourné.

Fenêtre de terminal
osv-scanner scan -L package-lock.json

Si le scan échoue (code 1), rien n'a été installé : vous n'avez fait que résoudre le lockfile. Annulez la modification et n'allez pas plus loin :

Fenêtre de terminal
git checkout -- package-lock.json

Le scan est vert (code 0) ? Les dépendances sont saines, vous pouvez installer pour de vrai.

Fenêtre de terminal
npm ci

Un script reste facultatif : on peut l'oublier. Le hook pre-commit rend le scan automatique : dès que le lockfile change, il s'exécute avant que la dépendance n'entre dans l'historique Git et ne parte vers vos collègues. OSV-Scanner n'a pas de hook publié sur le registre pre-commit, mais un hook local appelle directement le binaire.

Créez .pre-commit-config.yaml à la racine :

repos:
- repo: local
hooks:
- id: osv-scanner-npm
name: OSV-Scanner (npm lockfile)
entry: osv-scanner scan -L app/package-lock.json
language: system
files: ^app/package-lock\.json$
pass_filenames: false
- id: osv-scanner-uv
name: OSV-Scanner (uv lockfile)
entry: osv-scanner scan -L app-py/uv.lock
language: system
files: ^app-py/uv\.lock$
pass_filenames: false

Activez puis testez le hook :

Fenêtre de terminal
pre-commit install
pre-commit run --all-files

Sur un lockfile vérolé, le commit est refusé et la sortie liste les vulnérabilités. Corrigez la version fautive, puis recommitez.

Les étapes précédentes sécurisent votre poste. La CI est un autre niveau : le filet qui rattrape ce qui est passé entre les mailles — un collègue qui n'a pas le hook, un poste mal configuré. OSV-Scanner officiel s'y branche via des workflows réutilisables, en deux modes complémentaires, à épingler au SHA de la version (jamais un tag seul).

Le scan de pull request compare la branche cible à la branche de la PR et ne casse le build que si la PR introduit une nouvelle vulnérabilité — la dette préexistante ne bloque pas toute l'équipe :

name: OSV-Scanner PR
on:
pull_request:
branches: [main]
merge_group:
branches: [main]
permissions:
actions: read
security-events: write
contents: read
jobs:
osv-scan-pr:
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8

Le scan planifié rejoue une analyse complète à intervalle régulier. Il est indispensable : un paquet propre au moment du merge peut être reclassé MAL- quelques heures plus tard. Le cron rattrape ce que le scan de PR ne pouvait pas voir :

name: OSV-Scanner Scheduled
on:
schedule:
- cron: "30 12 * * 1"
push:
branches: [main]
permissions:
actions: read
security-events: write
contents: read
jobs:
osv-scan-scheduled:
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8

Ces workflows remontent leurs résultats au format SARIF dans l'onglet Code Scanning de GitHub, d'où les permissions security-events: write et actions: read. Ils scannent le dépôt entier : uv.lock et package-lock.json sont couverts sans configuration supplémentaire.

Prévention en amont : fermer la fenêtre d'exécution

Section intitulée « Prévention en amont : fermer la fenêtre d'exécution »

La détection ne suffit pas contre un malware du jour que la base OSV n'a pas encore classé. Deux réglages réduisent la surface, en complément du scanner.

D'abord, couper l'exécution des scripts d'installation, le principal vecteur. Ensuite, imposer un délai de quarantaine (cooldown) : n'installer que des versions publiées depuis assez longtemps pour avoir été analysées — la plupart des paquets malveillants sont retirés ou classés MAL- en 24 à 72 heures.

Dans le .npmrc du projet (cooldown disponible depuis npm 11.10.0) :

# Couper l'exécution des scripts pre/postinstall
ignore-scripts=true
# N'installer que les versions publiées il y a plus de 7 jours
min-release-age=7

OSV-Scanner ne remplace pas un artifact firewall, il le complète. Le firewall agit au périmètre : il empêche un paquet malveillant d'entrer dans le registre interne. OSV-Scanner agit sur le poste et la CI : il détecte ce qui est déjà dans le projet, y compris quand un développeur tire un paquet directement depuis npmjs.com, contournant le registre interne.

ContrôleQuandCe qu'il protège
Artifact firewallpérimètre / registreà l'ingestiontout ce qui passe par le registre interne
OSV-Scannerposte + CIà l'ajout, au commit, en CIle projet, même hors registre interne
Cooldown + scripts coupésposteà l'installationla fenêtre du malware non encore classé

Les trois reposent en partie sur les mêmes signatures : un paquet vraiment inconnu passe à travers. C'est pourquoi le cooldown reste la seule défense temporelle contre l'inédit.

Traitez OSV-Scanner comme tout outil exécuté en CI : une dépendance de votre pipeline, donc une surface d'attaque. Épinglez le workflow réutilisable au SHA (déjà fait plus haut) et n'accordez que les permissions minimales nécessaires — security-events: write pour publier le SARIF, rien de plus. N'ajoutez pas de token de registre privé au job de scan tant qu'il n'en a pas besoin : le scan lit des lockfiles, il n'installe rien.

SymptômeCause probableSolution
min-release-age ignorénpm < 11.10.0Mettre npm à jour (npm install -g npm@latest)
Le scan ne trouve aucun paquetLockfile absent ou mauvais chemin -LGénérer le lockfile (npm install --package-lock-only, uv lock)
no-build casse l'install d'un paquetPaquet publié uniquement en sdistRéautoriser ce paquet précis via no-build-package
Code de sortie 0 malgré des vulnérabilitésSortie redirigée vers head/grepTester $? sur la commande osv-scanner seule
Beaucoup de bruit sur la dette existanteScan complet sur une PRUtiliser le workflow PR-diff qui ne signale que le nouveau
  1. OSV-Scanner détecte vulnérabilités (CVE-) et paquets malveillants (MAL-).
  2. Il lit les lockfiles statiquement : on peut scanner avant d'installer.
  3. Le geste clé : résoudre le lockfile → scanner → installer seulement si vert.
  4. Le code de sortie 1 fait échouer hook et CI ; 0 = propre.
  5. Le pre-commit protège l'équipe ; il ne protège pas votre machine de l'exécution.
  6. En CI : scan de PR (nouveautés) + scan planifié (rattrape les MAL- tardifs).
  7. La détection ne couvre pas le malware du jour : ajoutez ignore-scripts/no-build et un cooldown.
  8. Scanner et artifact firewall sont deux étages complémentaires, pas un choix.

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