Skip to content

Repository files navigation

fad-checker

npm version npm downloads license node CI

AKA Formidable Auditor's Dependency Checker
AKA Fuckin' Autonomous Dependency Checker

fad-checker is a polyglot dependency auditor built for professional code audits.

It scans 10 ecosystems + 9 CMS/Frameworks (WordPress, Drupal, Symfony, Laravel…) in one pass, with no build tools, support air-gapped workflows using transferred caches, private package detection, committed binaries & certificates, then produces clean HTML reports + json baseline + (DOC/XLSX/SARIF/CycloneDX/etc) .

🌐 Project site & docs →

fad-checker animated terminal demo: an offline Maven audit — dependencies absent from Maven Central flagged as private/internal, the compact single-line vulnerability-database progress, then findings coloured by severity

Features

  • 10 ecosystems in one pass; Maven, Gradle, npm/Yarn/pnpm, Composer, PyPI, NuGet, Go, Ruby — plus vendored JS, committed native binaries (identified by checksum) and embedded JARs (fat-jars/war/ear, opened in-memory).
  • No build tools; No mvn/gradle/npm/pip/dotnet/go, no node_modules/ → how
  • CVE from multiple sources, merged & prioritised; CVEProject + OSV.dev + Packagist security advisories + NVD, ranked CISA KEV → EPSS → CVSS.
  • Beyond CVEs; Report EOL and out-of-active-support frameworks, deprecated/abandoned/yanked, outdated, SPDX licenses, and private/internal packages
  • CMS & frameworks audited as instances; Symfony, Laravel, WordPress, Drupal, Joomla, PrestaShop, TYPO3, Magento/Adobe Commerce and SPIP with per-instance inventory (core, plugins, themes, bundles, components) → the dedicated guide
  • Crypto material; committed certificates, private vs public keys across PEM/OpenSSH/PuTTY/PGP and JKS/PKCS#12 keystores.
  • Air-gapped flow; zero network under --offline → Benchmark · Air-gapped
  • Shared cache for a scanner fleet; fad-checker serve-cache + --proxy-cache → cache usage
  • Supply-chain risk; known-malicious advisories and suspected typosquats (--typosquat).
  • Audit-grade; every report carries a provenance manifest and a Methodology & limitations chapter; a SHA256SUMS;
  • Differential audits diff against a prior run (--baseline) and CI can gate on new findings only.
  • Reports in English or French (--lang fr)
  • Outputs & CI; Pro HTML report + JSON baseline by default + Word, Excel, CycloneDX 1.6 SBOM, CSAF 2.0 VEX, SARIF 2.1.0, JSON; gate with --fail-on, triage with --ignore/--vex.
  • Report made for productivity; every table / chart has a Copy for word button.

📖 Usage & all flags · Architecture · Comparison vs other tools · Data sources

Quick start

npm install -g fad-checker
fad-checker -s ./my-project          # → ./fad-checker-report/cve-report.html

A free NVD API key (instant) gives 10× faster enrichment: fad-checker --set-nvd-key YOUR_KEY. A few common runs; full list via fad-checker --help or docs/USAGE.md

Interactive HTML samples

These are standalone reports from real source scans, frozen on 2026-09-24. The CMS sample focuses on PHP dependencies; WordPress advisory coverage is explicitly incomplete without a Wordfence feed. Sample scope, sources and reproduction commands.

Warning

fad-checker is new and may still contain ( rare ) bugs. Treat its output as a strong first pass, double-check anything critical, and please report issues; they get fixed fast.

Why use fad-checker for code audits?

What it does for an audit that the others don't. Same column set and sourcing discipline as docs/COMPARISON.md — ⚠️ is partial and says how, cells are meant to be checkable.

What an auditor actually needs to do fad OSV Trivy Grype+Syft OWASP DC Snyk
Audit a 100-module polyglot monorepo in one command, with no toolchain installed ✅ 105 modules ⚠️ reactor skipped ⚠️ needs ~/.m2 ⚠️ opt-in ⚠️ Java build ⚠️ mvn build
Scan offline / air-gapped without dropping transitive deps ✅ 657/657 ❌ ⚠️ ~/.m2 ⚠️ opt-in ⚠️ mirror ❌
Identify the private/internal deps across a big project ✅ ❌ ❌ ❌ ❌ ❌
Extract cleaned deps descriptors into an external directory ✅ -t ❌ ❌ ❌ ❌ ❌
Report EOL / deprecated frameworks & deps, transitive ones included ✅ ⚠️ deprecated only ⚠️ OS distros only ❌ ❌ ⚠️ web UI only
Report committed keys & certificates ✅ ❌ ⚠️ key rule ❌ ❌ ❌
Spot committed binaries (.dll, .exe, …) and check them against their checksums ✅ ❌ ⚠️ some ⚠️ patterns ❌ ❌
Clearly list what was not scanned — before the client asks ✅ warnings + method ⚠️ log ⚠️ log ⚠️ log ⚠️ log ⚠️ log
Answer "against what data?" six months later ✅ ❌ ❌ ⚠️ DB date ⚠️ NVD date ❌
Send a report, not a JSON dump ✅ HTML + .doc ⚠️ HTML list ⚠️ template ❌ ⚠️ HTML list ⚠️ snyk-to-html
Charts, per-CVE drill-down and a pasteable Word copy ✅ ❌ ❌ ❌ ❌ ❌
Make delta reports showing only what changed ✅ --baseline ❌ ❌ ❌ ❌ ⚠️ cloud
Audit CMS/framework instances as such — plugins, themes, publisher advisories ✅ 9 products ❌ ❌ ❌ ❌ ❌
Share one cache across the fleet, API keys server-side ✅ serve-cache ❌ ⚠️ local DB ⚠️ local DB ⚠️ local DB ⚠️ cloud

Deliberately not a goal: reachability. A finding is a vulnerable version on the dependency graph, and the report says exactly that (in Methodology) instead of guessing at call paths. Deciding whether the vulnerable code is reachable in this application is the auditor's call, made with application context no scanner has.

More basic exemples :

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
fad-checker -s ./proj -r html,json,xlsx                        # include the Excel workbook
fad-checker -s ./site --app-plugins wordpress --private-component wp-content/plugins/acme --offline

Important

--offline reads the cache, it doesn't replace it. On a cold cache there is nothing to match against, so an offline first run legitimately reports 0 CVE / 0 EOL / 0 outdated; that's an empty cache, not a clean project. Warm it once (a normal online run on any project, or --import-cache), then --offline returns the full result set with zero network calls. Air-gapped machines get their cache via --export-cache / --import-cache.

What it finds

The report keeps the six root chapters. Sub-chapters appear only when they contain results and are numbered consecutively; application inventory and methodology remain available in scan context:

Chapter Source What it catches
0. Warnings (top) local heuristics Missing lockfiles, unresolved Maven versions (BOM-managed), private packages absent from configured registries
Δ. Changes since baseline (top, with --baseline) diff vs prior JSON New / fixed / unchanged findings per category + the list of new production CVEs; for repeat audits and --fail-on-new CI gating
1. CVE (X direct, Y indirect, Z dev) CVEProject + OSV.dev + Packagist + qualified publisher feeds + NVD/CPE Applications first when findings exist; CMS/framework findings by instance and owner · Production; public CVE / GHSA in other prod deps, per ecosystem, per manifest, prioritised by CISA KEV + EPSS + CVSS · Vendored JS vulns (retire.js) — one row per physical library, linked CVEs + CWEs on the row, every advisory behind a click · Dev (test/provided, dev/optional/peer) · Likely false positives (CPE-filtered)
2. Unmanaged / unversioned components deps.dev + CIRCL (by checksum), retire.js, built-in X.509 Embedded binaries; CVEs in libs shipped inside committed .jar/.war/.ear (fat-jars, shaded uber-jars) · Native binaries (.dll/.exe/.so/.dylib) identified by hash, flagged should-be-managed / name≠checksum / unknown / malicious · Vendored JavaScript inventory (jQuery, Bootstrap, …) vulnerable or not · Certificates & key material; committed certs (expiry / weak key / weak signature / self-signed), private vs public keys (PEM/OpenSSH/PuTTY/PGP/SSH) and keystores, all parsed offline
3. Maintenance / EOL (X EOL, Y obsolete, Z outdated) endoflife.date · curated + registry flags · Maven Central / npm / Packagist / PyPI / NuGet End-of-Life frameworks (+ an "Out of active support" band with --eol-support; Symfony/Laravel grouped as one row per framework; PHP runtime when the Composer constraint proves it), split direct (declared / parent-POM-inherited — bump these) vs transitive (bump the dep that pulls them in) · Obsolete / deprecated / abandoned / yanked · Outdated (newer version available, with release dates; direct deps only)
4. Licenses (opt-in: --licenses) registry metadata + Maven POMs → SPDX policy Each dep's license normalised to SPDX and classified; copyleft (GPL/AGPL/LGPL/MPL), proprietary and unknown flagged for review
5. Fix Recommendations computed Per-ecosystem pin recipes: Maven <dependencyManagement>, Gradle constraints { }, npm overrides, yarn resolutions, composer require, pip install, dotnet add package
6. Scan context & limitations provenance manifest + walk Scanned descriptors (every manifest parsed) · Ignored directories (pruned paths + rule) · Methodology, data sources & limitations (data-source freshness, run config, explicit statement of what fad-checker does not assess) · Application inventory & coverage (also shown when no CVE matches)
Supply-chain risk (cross-cutting) OSV MAL-… + name heuristic Known-malicious packages (always block the CI gate, any --fail-on level) and suspected typosquats (--typosquat: an npm/PyPI name one edit from a popular package; lodahs↔lodash)

The HTML report opens in any browser, contains every detail (CVSS vectors, references, full descriptions, CPE configurations, via-paths for transitives) and ships a Word-compatible .doc twin. Every match carries a composite priority (KEV-exploited > EPSS likelihood > CVSS severity), and the run can additionally emit a CycloneDX 1.6 SBOM (--report-sbom, vulnerabilities inline) and a CSAF 2.0 VEX (--report-csaf) for downstream tooling.

fad-checker HTML report; executive summary with severity tiles and a detailed CVE table with CWE, descriptions and fix versions

CMS & frameworks

See the CMS coverage limits and shared-cache operating limits.

fad-checker doesn't just read the composer.json under a WordPress or Drupal site — it inventories the instance: core, plugins, themes, bundles and framework components with their observed versions, attributes every dependency CVE to the component that ships it, and reports each instance in its own sub-chapter — synthesis included even when it comes out clean. Any recognized layout is activated by the default --app-plugins auto; none opts out.

Product Inventory Advisory lane
WordPress core (wp-includes/version.php), plugins (public or private by Update URI), themes Wordfence production feed (API key, or a warmed catalogue offline) + core checksums integrity (api.wordpress.org)
Drupal core (lock + Drupal.php marker), modules incl. modules/contrib, themes, profiles, Drupal 7 branch packages.drupal.org per-package security advisories
Symfony framework, framework-components, bundles, libraries; Symfony Flex recipes (symfony.lock) the dependency lanes (OSV.dev, Packagist, NVD) — no publisher feed exists, and the coverage says so
Laravel framework, bundles, libraries the dependency lanes (OSV.dev, Packagist, NVD)
PrestaShop core (_PS_VERSION_), modules, themes the publisher's GitHub security-advisories feed
TYPO3 core, extensions the publisher's GitHub security-advisories feed
SPIP core ($spip_version_branche in ecrire/inc_version.php), dist plugins (paquet.xml), user plugins (paquet.xml/legacy plugin.xml) NVD product CVEs (cpe:2.3:a:spip:spip) — the only machine-readable SPIP source; plugins stay honestly not-qualified
Joomla / Magento (Adobe Commerce) core, extensions/modules, themes no machine-readable publisher feed exists; components locked as Composer packages read as covered by the dependency lanes, the rest stays honestly not qualified. A Magento source distribution reports its exact version from the root composer.json

Every advisory snapshot a live lane fetches is stamped and cached in ~/.fad-checker/advisory-snapshots/, carried by --export-cache/--import-cache, warmed from the air-gapped descriptor itself by --import-anonymized, and reused automatically offline — the Wordfence API key never travels to the enclave. Private/custom components are inventoried separately and never sent to any publisher. → the dedicated guide · application usage

Air-gapped audits

Zero-data-sent guarantee. Under --offline, fad-checker makes no network calls whatsoever; it reads only the warmed ~/.fad-checker/ caches and never transmits a dependency, path or finding off the machine. It is regression-tested (test/offline-guarantee.test.js, a tripwire fetcher that throws if touched) and auditor-reproducible: unshare -rn node fad-checker.js -s ./proj --offline … runs it in a namespace with no network interface and yields byte-identical findings. Unlike the mainstream OSS scanners, fad also resolves the Maven transitive graph offline; so on an air-gapped multi-module project it finds the transitive CVEs they can't.

When the audited system is offline / confidential (typical of a regulated or air-gapped audit) it can't reach OSV / NVD / Maven Central / npm. Split the work across machines while keeping zero environment information off the secure enclave: an anonymized descriptor carries only public package coordinates; no filesystem paths, no registry URLs, no hostnames/usernames; and the detailed report is produced back on the offline machine.

The transfer relies on a property of fad-checker's caches: they are keyed by coordinate or vuln id, never by path, so they are machine-independent. The online step just warms the caches; the offline step replays the scan and gets cache hits.

# ── Phase 1; OFFLINE (audited machine): export the anonymized descriptor ──
# Exclude private/internal packages with -e (offline we can't tell private from public).
fad-checker -s ./proj -e "^(client|internal)\." --export-anonymized deps.json
#   → deps.json: public coordinates only. Review it before it leaves the enclave.

# ── Phase 2; ONLINE (any machine, no source needed): warm the caches ──
fad-checker --import-anonymized deps.json     # scans coordinates → OSV/NVD/CVE/registry/EOL + retire signatures
                                              #   + warms the CMS advisory snapshots (Drupal/PrestaShop/TYPO3 feeds,
                                              #   WP checksums per core version, Wordfence when a key is set)
fad-checker --export-cache fad-cache.tar.gz   # bundle the warmed ~/.fad-checker/

# ── Phase 3; OFFLINE (audited machine): full report, all local context ──
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
#   → full HTML/.doc report with manifests & structure, generated inside the enclave.
#   CMS advisory snapshots (Drupal/PrestaShop/TYPO3 feeds, WP checksums) fetched live by
#   the online phase ride the same archive and are consumed automatically — no flags.

What the descriptor (fad-deps/1) contains vs. drops:

Kept (needed to scan) Dropped (environment)
ecosystem, ecosystemType manifest paths / pom paths
namespace, name resolved registry URLs
version, versions integrity hashes
scope, isDev parent chains, lockfile type
application type + core version + inventoried public component identities private component identities

The online phase report is itself path-free; vendored-JavaScript (retire.js) findings are produced offline in phase 3, since retire needs the actual .js files; its signature DB is warmed online (phase 2) and carried by --export-cache. Full offline/cache control → docs/USAGE.md.

Docs

  • docs/USAGE.md; every flag and workflow: offline/cache control, private registries, config files, recipes, safety rails.
  • docs/CMS-FRAMEWORKS.md; the CMS/framework instance view: detection markers, per-product advisory lanes, coverage semantics and the air-gapped workflow.
  • docs/ARCHITECTURE.md; internals: codecs, collection, matching, report pipeline.
  • docs/COMPARISON.md; vs OSV-Scanner / Trivy / Grype / OWASP DC / Snyk, and how it stays build-free.
  • docs/BENCHMARK.md — reproducible air-gapped recall benchmark vs OSV-Scanner on a public 105-module project.
  • docs/DATA-SOURCES.md; the public datasets fad-checker uses + their licenses.
  • CHANGELOG.md · CLAUDE.md; release history · code-level orientation for contributors.

Contributing

The most useful contribution to a young scanner is telling it where it's wrong: run it on a real project and file a false positive / false negative report with the coordinate and the manifest snippet that produced it. Dev setup, ground rules and the codec extension point → CONTRIBUTING.md. Vulnerabilities in fad-checker itself → SECURITY.md (please report privately).

On AI assistance: this codebase is written with heavy use of Claude Code; CLAUDE.md in the repo root is exactly what it looks like. The bar it's held to is the one you can check yourself: 847 tests (npm test), the zero-network guarantee enforced by a tripwire test and reproducible under unshare -rn, and coverage numbers measured against a Snyk baseline rather than asserted. fad-checker itself uses no LLM at runtime; findings come from public vulnerability databases and deterministic parsers, and no report text is generated. Full statement, including where review actually caught a bad finding → AI_POLICY.md. Where the code doesn't meet that bar, that's a bug report I want.

License

MIT; see LICENSE.

About

One-shot polyglot dependency auditor (10 ecosystems + 9 CMS/Frameworks). No build tools. Real & complete air-gapped mode. Private deps, binaries, certs, EOL, CVE (KEV+EPSS) - Made for professional code audits.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages