
Auditeur de dépendances sans build qui analyse 10 écosystèmes hors ligne, signalant les CVE priorisées par CISA KEV et EPSS, les paquets en fin de vie, les licences, les clés commitées et les binaires avec exports SBOM et SARIF.
Formidable Auditor's Dependency Checker
AKA Fuckin' Autonomous Dependency Checker
fad-checker audite Maven · Gradle · npm · Yarn · pnpm · Composer · PyPI · NuGet · Go · Ruby, le JavaScript vendu, les binaires natifs commités et le matériel cryptographique (certificats et clés privées/publiques) dans n'importe quelle arborescence source ; multi-module, monorepo, polyglotte ; et produit un rapport HTML + Word autonome (CVE priorisées par EPSS + CISA KEV, EOL, obsolètes, périmées, licences) ainsi que des exports . ; il lit les lockfiles et les manifestes directement sur le disque.

mvn/gradle/npm install/pip/dotnet restore/go build, pas de node_modules/. Le graphe Maven est résolu de la manière dont Maven le résout. → comment--offline, testé en régression et reproductible sous unshare -rn. Sur Maven, il récupère 657/657 du résultat en ligne d'OSV-Scanner sans aucune interface réseau, contre 45 / 40 / 37 pour les autres. → Benchmark · Air-gapped--typosquat).SHA256SUMS ; les audits différentiels comparent à une exécution antérieure (--baseline) et la CI peut ne bloquer que sur les nouveaux constats.--help qui tient sur un écran ; la longue traîne de commutateurs se replie en quatre flags — -d eol,nvd désactive des choses, -a licenses,snyk active ce qui est désactivé par défaut, -r html,json choisit les sorties, -o dit où. Les flags individuels fonctionnent toujours et --help-all les liste.--lang fr).doc avec --report-doc), CycloneDX 1.6 SBOM, CSAF 2.0 VEX, SARIF 2.1.0, JSON ; gate avec --fail-on, triage avec --ignore/--vex. Registres privés pour chaque écosystème.Ce qu'il apporte à un audit que les autres n'apportent pas. Même jeu de colonnes et même discipline de sourçage que
docs/COMPARISON.md — ⚠️ signifie partiel et précise comment, les cellules sont censées être
vérifiables.
| Ce qu'un auditeur a réellement besoin de faire | fad | OSV | Trivy | Grype+Syft | OWASP DC | Snyk |
|---|---|---|---|---|---|---|
| Auditer un monorepo polyglotte de 100 modules en une commande, sans toolchain installée ¹ | ✅ 105 modules | ⚠️ reactor ignoré | ⚠️ nécessite ~/.m2 | ⚠️ opt-in | ⚠️ build Java | ⚠️ build mvn |
| Scanner hors ligne / air-gapped sans perdre les dépendances transitives ² | ✅ 657/657 | ❌ | ⚠️ ~/.m2 | ⚠️ opt-in | ⚠️ miroir | ❌ |
| Identifier les dépendances privées/internes dans un grand projet ³ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Extraire des descripteurs de dépendances nettoyés dans un répertoire externe ⁴ | ✅ -t | ❌ | ❌ | ❌ | ❌ | ❌ |
| Signaler les frameworks & dépendances EOL / dépréciés, transitifs inclus ⁵ | ✅ | ⚠️ dépréciés uniquement | ⚠️ distros OS uniquement | ❌ | ❌ | ⚠️ interface web uniquement |
| Signaler les clés & certificats commités ⁶ | ✅ | ❌ | ⚠️ règle clé | ❌ | ❌ | ❌ |
Repérer les binaires commités (.dll, .exe, …) et les vérifier par leurs checksums ⁷ | ✅ | ❌ | ⚠️ certains | ⚠️ motifs | ❌ | ❌ |
| Lister clairement ce qui n'a été scanné — avant que le client ne le demande ⁸ |
¹ Pas de mvn/go/npm/pip/dotnet — manifestes analysés sur le disque, rien d'installé ni d'exécuté. 105 × pom.xml en une passe : 790 paires contre 657 pour OSV-Scanner, 133 propres à fad, versions médiées par module et non aplaties.
² 657 sur 657 du résultat Maven en ligne d'OSV-Scanner, sous unshare -rn — aucune interface réseau. Testé par tripwire ; seules des coordonnées publiques quittent jamais l'enceinte.
³ Le chapitre 0 nomme chaque coordonnée pour laquelle chaque registre configuré a répondu 404 — Maven, npm, PyPI, NuGet, Composer, Go et RubyGems — avec le(s) manifeste(s) qui la déclarent. Un registre qui a expiré ou renvoyé une erreur n'est jamais compté : une réponse non concluante accuserait sinon un client de livrer des paquets internes parce que son proxy était instable. -e <regex> les exclut ensuite.
⁴ -t <dir> : POMs normalisés plus chaque lockfile non-Maven mis en miroir, coordonnées privées retirées. Archivable, et scannable par n'importe quoi — --snyk inclus.
⁵ endoflife.date, séparé direct vs transitif pour savoir quelle dépendance mettre à jour, plus déprécié / abandonné / retiré et périmé. Trivy ne couvre que les distros OS ; la santé des paquets de Snyk est web uniquement.
⁶ Inventaire et verdicts : expiration, RSA<2048, MD5/SHA1, auto-signé ; clés privées vs publiques ; JKS/PKCS#12. Parseur hors ligne. La règle de secrets de Trivy trouve le fichier, pas la faille.
⁷ Identifiés par hash via deps.dev + CIRCL → devrait-être-déclaré / nom≠checksum / inconnu / malveillant. Les motifs de Syft nomment une version, pas une identité.
⁸ Le chapitre 0 signale ce que ce scan n'a pas pu atteindre (lockfiles manquants, versions BOM-only, Yarn Berry, runtime PHP indéterminable) ; le chapitre 6.3 énonce ce que l'outil n'évalue jamais. Ailleurs, le premier est une ligne de log que l'audit ne voit jamais, le second n'est pas écrit.
⁹ Manifeste de provenance : outil, runtime, mode, configuration d'exécution et fraîcheur du cache pour les 13 sources. Grype et Dependency-Check portent la date d'une source, pas celle de l'exécution.
¹⁰ Chapitres 0→6 avec un résumé exécutif et des recettes de correction, HTML autonome plus un jumeau Word .doc. Aucun des autres n'émet du Word.
¹¹ Quatre graphiques SVG en ligne — CWE par pire sévérité, transitives vulnérables par dépendance racine, vos modules les plus vulnérables (direct vs transitif sur un projet mono-module), bandes de priorité de correction — rendus aussi dans le .doc, avec copie en un clic en PNG (ou un tableau en HTML riche) qui se colle dans Word formaté. Chaque CVE conserve son vecteur CVSS, CWE, références, configuration CPE et via-path derrière une exploration, sans aucune ressource externe.
¹² --baseline ajoute un chapitre Δ (nouveau / corrigé / inchangé) ; --fail-on-new ne bloque que sur les nouveaux constats. Snyk suit cela sur sa plateforme, pas comme un diff local.
Où il perd — conteneurs/paquets OS, PR de correction automatique, et couverture CVE face au flux
curé de Snyk → docs/COMPARISON.md ·
l'écart, mesuré.
Délibérément pas un objectif : l'atteignabilité. Un constat est une version vulnérable sur le graphe de dépendances, et le rapport dit exactement cela (ch. 6.3) au lieu de deviner les chemins d'appel. Décider si le code vulnérable est atteignable dans cette application relève de l'auditeur, avec un contexte applicatif qu'aucun scanner ne possède.
[!WARNING] fad-checker est nouveau et peut encore contenir (de rares) bugs. Traitez sa sortie comme une première passe solide, vérifiez deux fois tout ce qui est critique, et veuillez signaler les problèmes ; ils sont corrigés rapidement.
npm install -g fad-checker fad-checker -s ./my-project # → ./fad-checker-report/cve-report.html
Une [clé API NVD](https://nvd.nist.gov/developers/request-an-api-key) gratuite (instantanée) offre un enrichissement 10× plus rapide : `fad-checker --set-nvd-key YOUR_KEY`. Quelques exécutions courantes ; liste complète via `fad-checker --help` ou [docs/USAGE.md](https://github.com/9pings/fad-checker/blob/main/docs/USAGE.md) :```bash
fad-checker -s ./proj -e "^com\.acme\." # exclude private libs (coord regex)
fad-checker -s ./proj -t ../clean -e "^com\.acme\." # extract only: normalised descriptors, private modules flagged
fad-checker -s ./proj -t ../clean -e "^com\.acme\." -a snyk # same extraction + scan + merge Snyk
fad-checker -s ./proj --offline # fully offline (zero network, needs a warmed cache)
fad-checker -s ./proj -a osv-db,typosquat # offline-complete OSV + typosquat
fad-checker -s ./proj -a licenses --fail-on high # license chapter + CI gate
fad-checker -s ./proj --report-json --baseline last.json --fail-on-new # differential audit: fail CI on NEW findings
fad-checker diff last.json this.json # standalone diff of two findings JSONs
Ce que fait réellement -t <dir>. Il s'agit d'une étape d'extraction, pas d'un adaptateur Snyk. Elle écrit une
arborescence parallèle de descripteurs de dépendances normalisés : chaque pom.xml réduit aux
nœuds pertinents pour les dépendances (coordonnées, properties, dependencyManagement, dependencies,
modules), les parents de réacteur recâblés vers leur véritable relativePath dans l'arborescence, les ${…} résolus dans
les coordonnées — plus chaque lockfile/manifeste non-Maven dupliqué au même chemin relatif
(package-lock/yarn.lock/pnpm-lock, composer.lock, poetry/Pipfile/uv/pdm,
*.csproj/packages.lock.json, go.mod/go.sum, Gemfile.lock, et les compagnons comme
Directory.Packages.props ou nuget.config). En ligne, elle sonde également chaque coordonnée contre
les dépôts Maven configurés et signale celles qui n'y existent pas — vos
modules privés/internes — que -e <regex> retire ensuite des POM réécrits. Puis elle
s'arrête : pas de passe CVE/EOL et pas de rapport sauf si vous passez aussi --snyk, un --report-<type>,
--fail-on* ou --baseline. Ce que vous obtenez est un inventaire de dépendances assaini et sans build que vous pouvez
archiver comme preuve d'audit, remettre à un client ou à une revue juridique, ou pointer vers n'importe quel scanner — Snyk via
--snyk étant l'un d'eux.
[!IMPORTANT]
--offlinelit le cache, il ne le remplace pas. Sur un cache froid, il n'y a rien à comparer, donc une première exécution hors ligne rapporte légitimement 0 CVE / 0 EOL / 0 obsolète ; c'est un cache vide, pas un projet propre. Réchauffez-le une fois (une exécution en ligne normale sur n'importe quel projet, ou--import-cache), puis--offlinerenvoie l'ensemble complet des résultats sans aucun appel réseau. Les machines isolées obtiennent leur cache via--export-cache/--import-cache.
Un binaire unique autonome (sans Node), l'installation depuis les sources et la complétion shell sont dans → docs/USAGE.md.
Le rapport est organisé en chapitres racines (chacun regroupant des sous-chapitres liés) :
| Chapitre | Source | Ce qu'il détecte |
|---|---|---|
| 0. Avertissements (en haut) | heuristiques locales | Lockfiles manquants, versions Maven non résolues (gérées par BOM), bibliothèques privées absentes de Maven Central |
Δ. Changements depuis la baseline (en haut, avec --baseline) | diff vs JSON précédent | Constats nouveaux / corrigés / inchangés par catégorie + la liste des nouvelles CVE de production ; pour les audits répétés et le gating CI --fail-on-new |
| 1. CVE (X directes, Y indirectes, Z dev) | CVEProject + OSV.dev + NVD + CPE | 1.1 Production ; CVE publique / GHSA dans les dépendances de prod, par écosystème, par manifeste, priorisées par CISA KEV + EPSS + CVSS · 1.2 Vulnérabilités JS vendored (retire.js) · 1.3 Dev (test/provided, dev/optional/peer) · 1.4 Faux positifs probables (filtrés par CPE) |
| 2. Composants non gérés / non versionnés | deps.dev + CIRCL (par checksum), retire.js, X.509 intégré | 2.1 Binaires embarqués ; CVE dans les bibliothèques livrées dans des .jar/.war/.ear commités (fat-jars, uber-jars shaded) · 2.2 Binaires natifs (.dll/.exe/.so/.dylib) identifiés par hash, signalés comme devant être gérés / nom≠checksum / inconnu / malveillant · 2.3 Inventaire JavaScript vendored (jQuery, Bootstrap, …) vulnérable ou non · 2.4 Certificats & matériel de clé ; certificats commités (expiration / clé faible / signature faible / auto-signé), clés privées vs publiques (PEM/OpenSSH/PuTTY/PGP/SSH) et keystores, tous analysés hors ligne |
| 3. Maintenance / cycle de vie (X EOL, Y obsolètes, Z périmés) | endoflife.date · indicateurs curatés + registre · Maven Central / npm / Packagist / PyPI / NuGet | 3.1 Fin de vie des frameworks (+ une bande « Hors support actif » avec ; Symfony/Laravel regroupés en une ligne par framework ; runtime PHP lorsque la contrainte Composer le prouve), scindés (déclarés / hérités du POM parent — à mettre à jour) vs (mettez à jour la dépendance qui les tire) · · (version plus récente disponible, avec dates de publication ; dépendances directes uniquement) |
Le rapport HTML s'ouvre dans n'importe quel navigateur, contient chaque détail (vecteurs CVSS, références, descriptions complètes, configurations CPE, via-paths pour les transitives) et est livré avec un jumeau .doc compatible Word. Chaque correspondance porte une priorité composite (exploité par KEV > probabilité EPSS > sévérité CVSS), et l'exécution peut en outre émettre un SBOM CycloneDX 1.6 (--report-sbom, vulnérabilités en ligne) et un CSAF 2.0 VEX (--report-csaf) pour l'outillage en aval.

Aucun outil ne trouve tout. fad-checker mène à 87 % d'une union de 908 paires, et 131 paires sont revenues de Snyk et non de lui. Arbitrées une par une contre OSV, aucune n'est un bug de rappel :
| Verdict | |
|---|---|
| 57 | mauvais artefact — l'avis lie une coordonnée différente |
| 31 | hors plage — la version est en dehors de toute plage affectée déclarée |
| 23 | absent d'OSV — 19 identifiants SNYK-* propriétaires, 4 que seul NVD porte |
| 19 | aucune liaison Maven — l'avis ne lie aucun paquet Maven du tout |
| 1 | déjà rapporté, sous l'alias CVE |
| 0 | manque confirmé |
Deux tiers contredisent l'enregistrement public, donc les rapporter signifierait livrer des faux
positifs. CVE-2023-6481 est l'exemple limpide : revendiquée sur [email protected], elle lie
logback-core à [1.2.12, 1.2.13) — mauvais artefact, et une version publiée avant que la faille
n'existe.
Périmètre. Les 131 sont toutes de Snyk : OSV-Scanner, Trivy et Grype+Syft ont chacun contribué 0 constat que personne d'autre n'avait. Et toutes concernent la cible Maven — hors Maven, le graphe est dans le lockfile, chaque scanner lit la même entrée, et le benchmark mesure des ensembles de constats identiques sur npm, RubyGems et Composer.
C'est pourquoi --snyk existe. fad-checker prend la sortie de snyk test comme entrée et la fusionne,
de sorte que vous obtenez l'union plutôt que de choisir un camp. Un choix de couverture, pas une correction.
Méthode, mises en garde et verdicts par paire → docs/BENCHMARK.md ; à reproduire
avec scripts/adjudicate-gap.js.
Garantie zéro donnée envoyée. Sous
--offline, fad-checker n'effectue aucun appel réseau quel qu'il soit ; il lit uniquement les caches~/.fad-checker/réchauffés et ne transmet jamais une dépendance, un chemin ou un constat hors de la machine. C'est testé en régression (test/offline-guarantee.test.js, un fetcher-piège qui lève une exception s'il est touché) et reproductible par l'auditeur :unshare -rn node fad-checker.js -s ./proj --offline …l'exécute dans un namespace sans interface réseau et produit des constats identiques au byte près. Contrairement aux scanners OSS grand public, fad résout aussi le graphe transitif Maven hors ligne ; ainsi, sur un projet multi-modules isolé, il trouve les CVE transitives qu'ils ne peuvent pas trouver.
Lorsque le système audité est hors ligne / confidentiel (typique d'un audit réglementé ou isolé), il ne peut pas atteindre OSV / NVD / Maven Central / npm. Répartissez le travail entre machines tout en gardant zéro information d'environnement hors de l'enceinte sécurisée : un descripteur anonymisé ne porte que des coordonnées de paquets publics ; aucun chemin de système de fichiers, aucune URL de registre, aucun nom d'hôte/nom d'utilisateur ; et le rapport détaillé est produit de retour sur la machine hors ligne.
Le transfert repose sur une propriété des caches de fad-checker : ils sont indexés par coordonnée ou id de vulnérabilité, jamais par chemin, donc ils sont indépendants de la machine. L'étape en ligne ne fait que réchauffer les caches ; l'étape hors ligne rejoue le scan et obtient des hits de cache.```bash
fad-checker -s ./proj -e "^(client|internal)." --export-anonymized deps.json
fad-checker --import-anonymized deps.json # scans coordinates → OSV/NVD/CVE/registry/EOL + retire signatures fad-checker --export-cache fad-cache.tar.gz # bundle the warmed ~/.fad-checker/
fad-checker --import-cache fad-cache.tar.gz # merged into the enclave's own cache fad-checker -s ./proj --offline # re-collect locally (real paths) + cache hits
Ce que le descripteur (`fad-deps/1`) contient vs. abandonne :
| Conservé (nécessaire pour scanner) | Abandonné (environnement) |
| --- | --- |
| ecosystem, ecosystemType | chemins de manifest / chemins de pom |
| namespace, name | URLs de registre résolues |
| version, versions | hachages d'intégrité |
| scope, isDev | chaînes parentes, type de lockfile |
Le rapport de la phase en ligne est lui-même sans chemin ; les résultats pour le JavaScript vendu (retire.js) sont
produits **hors ligne en phase 3**, car retire a besoin des fichiers `.js` réels ; sa base de signatures
est préchauffée en ligne (phase 2) et transportée par `--export-cache`. Contrôle hors ligne/cache complet →
[`docs/USAGE.md`](https://github.com/9pings/fad-checker/blob/main/docs/USAGE.md).
## Docs
- [`docs/USAGE.md`](https://github.com/9pings/fad-checker/blob/main/docs/USAGE.md) ; chaque option et workflow : contrôle hors ligne/cache, registres privés, fichiers de configuration, recettes, garde-fous.
- [`docs/ARCHITECTURE.md`](https://github.com/9pings/fad-checker/blob/main/docs/ARCHITECTURE.md) ; internes : codecs, collecte, correspondance, pipeline de rapport.
- [`docs/COMPARISON.md`](https://github.com/9pings/fad-checker/blob/main/docs/COMPARISON.md) ; vs OSV-Scanner / Trivy / Grype / OWASP DC / Snyk, et comment il reste sans build.
- [`docs/BENCHMARK.md`](https://github.com/9pings/fad-checker/blob/main/docs/BENCHMARK.md) — benchmark de rappel reproductible en air-gapped vs OSV-Scanner sur un projet public de 105 modules.
- [`docs/DATA-SOURCES.md`](https://github.com/9pings/fad-checker/blob/main/docs/DATA-SOURCES.md) ; les jeux de données publics utilisés par fad-checker + leurs licences.
- [`docs/SPEC-audit-pro.md`](https://github.com/9pings/fad-checker/blob/main/docs/SPEC-audit-pro.md) ; les fonctionnalités de niveau audit (provenance, audit différentiel, méthodologie/intégrité) et pourquoi chacune a été conçue ainsi.
- [`CHANGELOG.md`](https://github.com/9pings/fad-checker/blob/main/CHANGELOG.md) · [`CLAUDE.md`](https://github.com/9pings/fad-checker/blob/main/CLAUDE.md) ; historique des versions · orientation au niveau du code pour les contributeurs.
## Contribuer
La contribution la plus utile à un scanner jeune est de **lui dire où il se trompe** : exécutez-le sur un
projet réel et déposez un [rapport de faux positif / faux négatif](https://github.com/9pings/fad-checker/issues/new?template=false_positive.yml)
avec la coordonnée et l'extrait de manifest qui l'a produit. Configuration de développement, règles de base et le
point d'extension des codecs → [`CONTRIBUTING.md`](https://github.com/9pings/fad-checker/blob/main/CONTRIBUTING.md). Vulnérabilités dans fad-checker
lui-même → [`SECURITY.md`](https://github.com/9pings/fad-checker/blob/main/SECURITY.md) (veuillez signaler en privé).
**À propos de l'assistance IA :** cette base de code est écrite avec un usage intensif de Claude Code ; [`CLAUDE.md`](https://github.com/9pings/fad-checker/blob/main/CLAUDE.md)
à la racine du dépôt est exactement ce à quoi cela ressemble. La barre à laquelle il est tenu est celle que vous pouvez vérifier
vous-même : **847 tests** (`npm test`), la garantie de zéro réseau imposée par un test tripwire et
reproductible sous `unshare -rn`, et des chiffres de couverture mesurés par rapport à une baseline Snyk plutôt
qu'affirmés. `fad-checker` lui-même n'utilise **aucun LLM à l'exécution** ; les résultats proviennent de bases de
vulnérabilités publiques et de parseurs déterministes, et aucun texte de rapport n'est généré. Déclaration
complète, y compris où la revue a réellement attrapé un mauvais résultat →
[`AI_POLICY.md`](https://github.com/9pings/fad-checker/blob/main/AI_POLICY.md). Là où le code n'atteint pas cette barre, c'est un rapport de bug que je veux.
## Licence
MIT ; voir [`LICENSE`](https://github.com/9pings/fad-checker/blob/main/LICENSE).
| ✅ ch. 0 + 6.3 |
| ⚠️ log |
| ⚠️ log |
| ⚠️ log |
| ⚠️ log |
| ⚠️ log |
| Répondre « sur la base de quelles données ? » six mois plus tard ⁹ | ✅ | ❌ | ❌ | ⚠️ date DB | ⚠️ date NVD | ❌ |
| Envoyer un rapport, pas un dump JSON ¹⁰ | ✅ HTML + .doc | ⚠️ liste HTML | ⚠️ template | ❌ | ⚠️ liste HTML | ⚠️ snyk-to-html |
| Graphiques, exploration par CVE et copie Word collable ¹¹ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Produire des rapports delta ne montrant que ce qui a changé ¹² | ✅ --baseline | ❌ | ❌ | ❌ | ❌ | ⚠️ cloud |
--eol-support4. Licences (opt-in : --licenses) | métadonnées de registre + POM Maven → politique SPDX | La licence de chaque dépendance normalisée en SPDX et classifiée ; copyleft (GPL/AGPL/LGPL/MPL), propriétaire et inconnue signalées pour revue |
| 5. Recommandations de correction | calculées | Recettes de pin par écosystème : Maven <dependencyManagement>, Gradle constraints { }, npm overrides, yarn resolutions, composer require, pip install, dotnet add package |
| 6. Contexte de scan & limitations | manifeste de provenance + parcours | 6.1 Descripteurs scannés (chaque manifeste analysé) · 6.2 Répertoires ignorés (chemins élagués + règle) · 6.3 Méthodologie, sources de données & limitations (fraîcheur des sources de données, configuration d'exécution, déclaration explicite de ce que fad-checker n'évalue pas) |
| Risque de chaîne d'approvisionnement (transversal) | OSV MAL-… + heuristique de nom | Paquets connus comme malveillants (bloquent toujours le gate CI, quel que soit le niveau --fail-on) et typosquats suspectés (--typosquat : un nom npm/PyPI à une édition d'un paquet populaire ; lodahs↔lodash) |