
Auditor de dependencias sin compilación que escanea 10 ecosistemas sin conexión, reportando CVEs priorizados por CISA KEV y EPSS, paquetes EOL, licencias, claves comprometidas y binarios con exportaciones SBOM y SARIF.
Formidable Auditor's Dependency Checker
También conocido como Fuckin' Autonomous Dependency Checker
fad-checker audita Maven · Gradle · npm · Yarn · pnpm · Composer · PyPI · NuGet · Go · Ruby, JavaScript vendorizado, binarios nativos comprometidos y material criptográfico (certificados y claves privadas/públicas) en cualquier árbol de código fuente; multi-módulo, monorepo, políglota; y produce un informe HTML + Word autocontenido (CVE priorizadas por EPSS + CISA KEV, EOL, obsoletas, desactualizadas, licencias) más exportaciones . ; lee los lockfiles y manifiestos directamente del disco.

mvn/gradle/npm install/pip/dotnet restore/go build, sin node_modules/. El grafo de Maven se resuelve tal como lo resuelve Maven. → cómo--offline, probado con regresión y reproducible bajo unshare -rn. En Maven recupera 657/657 del resultado online de OSV-Scanner sin ninguna interfaz de red, frente a 45 / 40 / 37 de los demás. → Benchmark · Air-gapped--typosquat).SHA256SUMS; las auditorías diferenciales comparan con una ejecución previa (--baseline) y la CI puede bloquear solo con los hallazgos nuevos.--help que cabe en una pantalla; la larga cola de opciones se pliega en cuatro flags — -d eol,nvd desactiva cosas, -a licenses,snyk activa lo que está desactivado por defecto, -r html,json elige las salidas, -o indica dónde. Los flags individuales siguen funcionando y --help-all los lista.--lang fr).doc con --report-doc), CycloneDX 1.6 SBOM, CSAF 2.0 VEX, SARIF 2.1.0, JSON; bloquea con --fail-on, clasifica con --ignore/--vex. Registros privados para cada ecosistema.Lo que hace para una auditoría que los demás no hacen. Mismo conjunto de columnas y disciplina de fuentes que
docs/COMPARISON.md — ⚠️ es parcial e indica cómo, las celdas están pensadas para ser
verificables.
| Lo que un auditor realmente necesita hacer | fad | OSV | Trivy | Grype+Syft | OWASP DC | Snyk |
|---|---|---|---|---|---|---|
| Auditar un monorepo políglota de 100 módulos en un solo comando, sin toolchain instalado ¹ | ✅ 105 módulos | ⚠️ reactor omitido | ⚠️ necesita ~/.m2 | ⚠️ opt-in | ⚠️ build Java | ⚠️ build mvn |
| Escanear offline / air-gapped sin perder dependencias transitivas ² | ✅ 657/657 | ❌ | ⚠️ ~/.m2 | ⚠️ opt-in | ⚠️ mirror | ❌ |
| Identificar las dependencias privadas/internas en un proyecto grande ³ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Extraer descriptores de dependencias limpias a un directorio externo ⁴ | ✅ -t | ❌ | ❌ | ❌ | ❌ | ❌ |
| Reportar frameworks y dependencias EOL / deprecadas, incluidas las transitivas ⁵ | ✅ | ⚠️ solo deprecadas | ⚠️ solo distros OS | ❌ | ❌ | ⚠️ solo web UI |
| Reportar claves y certificados comprometidos ⁶ | ✅ | ❌ | ⚠️ regla de claves | ❌ | ❌ | ❌ |
Detectar binarios comprometidos (.dll, .exe, …) y verificarlos contra sus checksums ⁷ | ✅ | ❌ | ⚠️ algunos | ⚠️ patrones | ❌ | ❌ |
| Listar claramente lo que se escaneó — antes de que lo pregunte el cliente ⁸ |
¹ Sin mvn/go/npm/pip/dotnet — manifiestos analizados del disco, nada instalado ni ejecutado. 105 × pom.xml en una pasada: 790 pares frente a los 657 de OSV-Scanner, 133 solo de fad, versiones mediadas por módulo no aplanadas.
² 657 de 657 del resultado online de Maven de OSV-Scanner, bajo unshare -rn — sin interfaz de red. Probado con tripwire; solo coordenadas públicas salen alguna vez del enclave.
³ El capítulo 0 nombra cada coordenada para la que cada registro configurado respondió 404 — Maven, npm, PyPI, NuGet, Composer, Go y RubyGems — con el/los manifiesto(s) que la declaran. Un registro que expiró o dio error nunca se cuenta: una respuesta no concluyente acusaría de otro modo a un cliente de distribuir paquetes internos porque su proxy falló. -e <regex> luego las excluye.
⁴ -t <dir>: POMs normalizados más cada lockfile no-Maven replicado, coordenadas privadas eliminadas. Archivable, y escaneable por cualquier cosa — --snyk incluido.
⁵ endoflife.date, dividido directo vs transitivo para que sepas qué dependencia actualizar, más deprecadas / abandonadas / retiradas y desactualizadas. Trivy cubre solo distros OS; la salud de paquetes de Snyk es solo web.
⁶ Inventario y veredictos: caducidad, RSA<2048, MD5/SHA1, autofirmados; claves privadas vs públicas; JKS/PKCS#12. Parser offline. La regla de secretos de Trivy encuentra el archivo, no el defecto.
⁷ Identificados por hash vía deps.dev + CIRCL → debería-declararse / nombre≠checksum / desconocido / malicioso. Los patrones de Syft nombran una versión, no una identidad.
⁸ El capítulo 0 señala lo que este escaneo no pudo alcanzar (lockfiles faltantes, versiones solo-BOM, Yarn Berry, runtime PHP indeterminable); el capítulo 6.3 declara lo que la herramienta nunca evalúa. En otros, lo primero es una línea de log que la auditoría nunca ve, lo segundo no está escrito.
⁹ Manifiesto de procedencia: herramienta, runtime, modo, configuración de ejecución y frescura de caché para las 13 fuentes. Grype y Dependency-Check llevan la fecha de una fuente, no de la ejecución.
¹⁰ Capítulos 0→6 con un resumen ejecutivo y recetas de corrección, HTML autocontenido más un gemelo Word .doc. Ninguno de los demás emite Word.
¹¹ Cuatro gráficos SVG en línea — CWE por peor severidad, transitivas vulnerables por dependencia raíz, tus módulos más vulnerables (directas vs transitivas en un proyecto de un solo módulo), bandas de prioridad de corrección — renderizados también en el .doc, con copia en un clic como PNG (o una tabla como HTML enriquecido) que se pega en Word con formato. Cada CVE conserva su vector CVSS, CWE, referencias, configuración CPE y via-path tras un desglose, con cero recursos externos.
¹² --baseline añade un capítulo Δ (nuevas / corregidas / sin cambios); --fail-on-new bloquea solo con hallazgos nuevos. Snyk rastrea esto en su plataforma, no como un diff local.
Dónde pierde — contenedores/paquetes OS, PRs de corrección automática, y cobertura de CVE frente al feed curado de Snyk → docs/COMPARISON.md ·
la brecha, medida.
Deliberadamente no es un objetivo: la alcanzabilidad. Un hallazgo es una versión vulnerable en el grafo de dependencias, y el informe dice exactamente eso (cap. 6.3) en lugar de adivinar rutas de llamada. Decidir si el código vulnerable es alcanzable en esta aplicación es decisión del auditor, tomada con contexto de la aplicación que ningún escáner tiene.
[!WARNING] fad-checker es nuevo y aún puede contener ( raros ) bugs. Trata su salida como una sólida primera pasada, verifica dos veces cualquier cosa crítica, y por favor reporta problemas; se corrigen rápido.
npm install -g fad-checker fad-checker -s ./my-project # → ./fad-checker-report/cve-report.html
Una [clave de API de NVD](https://nvd.nist.gov/developers/request-an-api-key) gratuita (instantánea) proporciona un enriquecimiento 10× más rápido: `fad-checker --set-nvd-key YOUR_KEY`. Algunas ejecuciones comunes; lista completa mediante `fad-checker --help` o [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
Qué hace realmente -t <dir>. Es un paso de extracción, no un adaptador de Snyk. Escribe un
árbol paralelo de descriptores de dependencias normalizados: cada pom.xml reducido a los
nodos relevantes para dependencias (coordenadas, properties, dependencyManagement, dependencies,
modules), los padres del reactor recableados a su relativePath real dentro del árbol, ${…} resuelto en
coordenadas — más cada lockfile/manifiesto no-Maven replicado en la misma ruta relativa
(package-lock/yarn.lock/pnpm-lock, composer.lock, poetry/Pipfile/uv/pdm,
*.csproj/packages.lock.json, go.mod/go.sum, Gemfile.lock, y acompañantes como
Directory.Packages.props o nuget.config). En línea también sondea cada coordenada contra
los repositorios Maven configurados y reporta las que no existen allí — tus
módulos privados/internos — que -e <regex> luego elimina de los POMs reescritos. Después
se detiene: sin pasada de CVE/EOL y sin informe a menos que también pases --snyk, un --report-<type>,
--fail-on* o --baseline. Lo que obtienes es un inventario de dependencias sanitizado y sin build que puedes
archivar como evidencia de auditoría, entregar a un cliente o a una revisión legal, o apuntar cualquier escáner hacia él — Snyk vía
--snyk siendo uno de ellos.
[!IMPORTANT]
--offlinelee la caché, no la reemplaza. En una caché fría no hay nada contra lo que comparar, así que una primera ejecución offline legítimamente reporta 0 CVE / 0 EOL / 0 desactualizados; eso es una caché vacía, no un proyecto limpio. Caliéntala una vez (una ejecución normal en línea sobre cualquier proyecto, o--import-cache), luego--offlinedevuelve el conjunto completo de resultados con cero llamadas de red. Las máquinas aisladas obtienen su caché vía--export-cache/--import-cache.
Un único binario autocontenido (sin Node), la instalación desde el código fuente y el autocompletado de shell están en → docs/USAGE.md.
El informe se organiza en capítulos raíz (cada uno agrupando subcapítulos relacionados):
| Capítulo | Fuente | Qué detecta |
|---|---|---|
| 0. Advertencias (arriba) | heurísticas locales | Lockfiles ausentes, versiones Maven sin resolver (gestionadas por BOM), librerías privadas que no están en Maven Central |
Δ. Cambios desde la línea base (arriba, con --baseline) | diff vs JSON previo | Hallazgos nuevos / corregidos / sin cambios por categoría + la lista de nuevos CVE de producción; para auditorías repetidas y el control de CI con --fail-on-new |
| 1. CVE (X directos, Y indirectos, Z dev) | CVEProject + OSV.dev + NVD + CPE | 1.1 Producción; CVE público / GHSA en dependencias de prod, por ecosistema, por manifiesto, priorizados por CISA KEV + EPSS + CVSS · 1.2 Vulnerabilidades de JS embebido (retire.js) · 1.3 Dev (test/provided, dev/optional/peer) · 1.4 Probables falsos positivos (filtrados por CPE) |
| 2. Componentes no gestionados / sin versión | deps.dev + CIRCL (por checksum), retire.js, X.509 integrado | 2.1 Binarios embebidos; CVE en librerías incluidas dentro de .jar/.war/.ear versionados (fat-jars, uber-jars con shading) · 2.2 Binarios nativos (.dll/.exe/.so/.dylib) identificados por hash, marcados como deberían-gestionarse / nombre≠checksum / desconocido / malicioso · 2.3 Inventario de JavaScript embebido (jQuery, Bootstrap, …) vulnerable o no · 2.4 Certificados y material de claves; certificados versionados (caducidad / clave débil / firma débil / autofirmado), claves privadas vs públicas (PEM/OpenSSH/PuTTY/PGP/SSH) y keystores, todo analizado offline |
| 3. Mantenimiento / ciclo de vida (X EOL, Y obsoletos, Z desactualizados) | endoflife.date · flags curados + de registro · Maven Central / npm / Packagist / PyPI / NuGet | 3.1 Fin de vida de frameworks (+ una banda "Fuera de soporte activo" con ; Symfony/Laravel agrupados como una fila por framework; runtime de PHP cuando la restricción de Composer lo demuestra), dividido en (declarados / heredados del POM padre — actualiza estos) vs (actualiza la dependencia que los arrastra) · · (hay versión más nueva disponible, con fechas de publicación; solo dependencias directas) |
El informe HTML se abre en cualquier navegador, contiene cada detalle (vectores CVSS, referencias, descripciones completas, configuraciones CPE, rutas de entrada para transitivas) e incluye un gemelo .doc compatible con Word. Cada coincidencia lleva una prioridad compuesta (explotado en KEV > probabilidad EPSS > severidad CVSS), y la ejecución puede además emitir un SBOM CycloneDX 1.6 (--report-sbom, vulnerabilidades en línea) y un CSAF 2.0 VEX (--report-csaf) para herramientas posteriores.

Ninguna herramienta lo encuentra todo. fad-checker lidera con el 87% de una unión de 908 pares, y 131 pares vinieron de Snyk y no de él. Adjudicados uno por uno contra OSV, ninguno es un fallo de recall:
| Veredicto | |
|---|---|
| 57 | artefacto incorrecto — el aviso vincula una coordenada diferente |
| 31 | fuera de rango — la versión está fuera de todo rango afectado declarado |
| 23 | no está en OSV — 19 ids SNYK-* propietarios, 4 que solo lleva NVD |
| 19 | sin vinculación Maven — el aviso no vincula ningún paquete Maven en absoluto |
| 1 | ya reportado, bajo el alias CVE |
| 0 | omisión confirmada |
Dos tercios contradicen el registro público, así que reportarlos significaría enviar falsos
positivos. CVE-2023-6481 es el ejemplo claro: atribuido a [email protected], vincula
logback-core en [1.2.12, 1.2.13) — artefacto incorrecto, y una versión publicada antes de que el fallo
existiera.
Alcance. Los 131 son de Snyk: OSV-Scanner, Trivy y Grype+Syft contribuyeron cada uno con 0 hallazgos que nadie más tuviera. Y todos están en el objetivo Maven — fuera de Maven el grafo está en el lockfile, todos los escáneres leen la misma entrada, y el benchmark mide conjuntos de hallazgos idénticos en npm, RubyGems y Composer.
Por eso existe --snyk. fad-checker toma la salida de snyk test como una entrada y la fusiona, así obtienes
la unión en lugar de elegir un bando. Una decisión de cobertura, no una corrección.
Método, advertencias y los veredictos por par → docs/BENCHMARK.md; reproduce
con scripts/adjudicate-gap.js.
Garantía de cero datos enviados. Bajo
--offline, fad-checker no hace ninguna llamada de red en absoluto; solo lee las cachés calentadas de~/.fad-checker/y nunca transmite una dependencia, ruta o hallazgo fuera de la máquina. Está probado contra regresiones (test/offline-guarantee.test.js, un fetcher trampa que lanza un error si se toca) y es reproducible por el auditor:unshare -rn node fad-checker.js -s ./proj --offline …lo ejecuta en un namespace sin interfaz de red y produce hallazgos idénticos byte a byte. A diferencia de los escáneres OSS convencionales, fad también resuelve el grafo transitivo de Maven offline; así que en un proyecto multi-módulo aislado encuentra los CVE transitivos que ellos no pueden.
Cuando el sistema auditado está offline / es confidencial (típico de una auditoría regulada o aislada) no puede alcanzar OSV / NVD / Maven Central / npm. Divide el trabajo entre máquinas manteniendo cero información del entorno fuera del enclave seguro: un descriptor anonimizado lleva solo coordenadas de paquetes públicos; sin rutas de sistema de archivos, sin URLs de registro, sin nombres de host/usuarios; y el informe detallado se produce de vuelta en la máquina offline.
La transferencia se apoya en una propiedad de las cachés de fad-checker: están indexadas por coordenada o id de vulnerabilidad, nunca por ruta, así que son independientes de la máquina. El paso en línea solo calienta las cachés; el paso offline reproduce el escaneo y obtiene aciertos de caché.```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
Qué contiene el descriptor (`fad-deps/1`) frente a lo que descarta:
| Conservado (necesario para escanear) | Descartado (entorno) |
| --- | --- |
| ecosystem, ecosystemType | rutas de manifiestos / rutas de pom |
| namespace, name | URLs de registro resueltas |
| version, versions | hashes de integridad |
| scope, isDev | cadenas padre, tipo de lockfile |
El informe de la fase en línea no contiene rutas en sí mismo; los hallazgos de JavaScript vendorizado (retire.js) se producen **sin conexión en la fase 3**, ya que retire necesita los archivos `.js` reales; su base de datos de firmas se precalienta en línea (fase 2) y se transporta mediante `--export-cache`. Control total sin conexión/caché →
[`docs/USAGE.md`](https://github.com/9pings/fad-checker/blob/main/docs/USAGE.md).
## Documentación
- [`docs/USAGE.md`](https://github.com/9pings/fad-checker/blob/main/docs/USAGE.md); cada flag y flujo de trabajo: control sin conexión/caché, registros privados, archivos de configuración, recetas, barreras de seguridad.
- [`docs/ARCHITECTURE.md`](https://github.com/9pings/fad-checker/blob/main/docs/ARCHITECTURE.md); aspectos internos: códecs, recopilación, emparejamiento, canalización de informes.
- [`docs/COMPARISON.md`](https://github.com/9pings/fad-checker/blob/main/docs/COMPARISON.md); frente a OSV-Scanner / Trivy / Grype / OWASP DC / Snyk, y cómo se mantiene libre de compilación.
- [`docs/BENCHMARK.md`](https://github.com/9pings/fad-checker/blob/main/docs/BENCHMARK.md) — benchmark de recall reproducible en entorno aislado frente a OSV-Scanner en un proyecto público de 105 módulos.
- [`docs/DATA-SOURCES.md`](https://github.com/9pings/fad-checker/blob/main/docs/DATA-SOURCES.md); los conjuntos de datos públicos que usa fad-checker + sus licencias.
- [`docs/SPEC-audit-pro.md`](https://github.com/9pings/fad-checker/blob/main/docs/SPEC-audit-pro.md); las características de nivel auditoría (procedencia, auditoría diferencial, metodología/integridad) y por qué cada una se construyó de esa manera.
- [`CHANGELOG.md`](https://github.com/9pings/fad-checker/blob/main/CHANGELOG.md) · [`CLAUDE.md`](https://github.com/9pings/fad-checker/blob/main/CLAUDE.md); historial de versiones · orientación a nivel de código para colaboradores.
## Contribuir
La contribución más útil para un escáner joven es **decirle dónde se equivoca**: ejecútalo en un
proyecto real y presenta un [informe de falso positivo / falso negativo](https://github.com/9pings/fad-checker/issues/new?template=false_positive.yml)
con la coordenada y el fragmento de manifiesto que lo produjo. Configuración de desarrollo, reglas básicas y el
punto de extensión de códecs → [`CONTRIBUTING.md`](https://github.com/9pings/fad-checker/blob/main/CONTRIBUTING.md). Vulnerabilidades en fad-checker
en sí → [`SECURITY.md`](https://github.com/9pings/fad-checker/blob/main/SECURITY.md) (por favor, repórtalas de forma privada).
**Sobre la asistencia de IA:** este código se escribe con un uso intensivo de Claude Code; [`CLAUDE.md`](https://github.com/9pings/fad-checker/blob/main/CLAUDE.md)
en la raíz del repositorio es exactamente lo que parece. El listón que se le exige es el que puedes comprobar
tú mismo: **847 tests** (`npm test`), la garantía de red cero impuesta por un test trampa y
reproducible bajo `unshare -rn`, y cifras de cobertura medidas contra una línea base de Snyk en lugar
de afirmadas. `fad-checker` en sí **no usa ningún LLM en tiempo de ejecución**; los hallazgos provienen de bases de datos
públicas de vulnerabilidades y analizadores deterministas, y no se genera ningún texto de informe. Declaración
completa, incluido dónde la revisión realmente detectó un hallazgo erróneo →
[`AI_POLICY.md`](https://github.com/9pings/fad-checker/blob/main/AI_POLICY.md). Donde el código no cumple ese listón, eso es un informe de error que quiero.
## Licencia
MIT; consulta [`LICENSE`](https://github.com/9pings/fad-checker/blob/main/LICENSE).
| ✅ cap. 0 + 6.3 |
| ⚠️ log |
| ⚠️ log |
| ⚠️ log |
| ⚠️ log |
| ⚠️ log |
| Responder "¿contra qué datos?" seis meses después ⁹ | ✅ | ❌ | ❌ | ⚠️ fecha BD | ⚠️ fecha NVD | ❌ |
| Enviar un informe, no un volcado JSON ¹⁰ | ✅ HTML + .doc | ⚠️ lista HTML | ⚠️ plantilla | ❌ | ⚠️ lista HTML | ⚠️ snyk-to-html |
| Gráficos, desglose por CVE y una copia pegable en Word ¹¹ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Generar informes delta mostrando solo lo que cambió ¹² | ✅ --baseline | ❌ | ❌ | ❌ | ❌ | ⚠️ nube |
--eol-support4. Licencias (opcional: --licenses) | metadatos de registro + POMs de Maven → política SPDX | La licencia de cada dependencia normalizada a SPDX y clasificada; copyleft (GPL/AGPL/LGPL/MPL), propietaria y desconocida marcadas para revisión |
| 5. Recomendaciones de corrección | calculado | Recetas de fijación por ecosistema: Maven <dependencyManagement>, Gradle constraints { }, npm overrides, yarn resolutions, composer require, pip install, dotnet add package |
| 6. Contexto del escaneo y limitaciones | manifiesto de procedencia + recorrido | 6.1 Descriptores escaneados (cada manifiesto analizado) · 6.2 Directorios ignorados (rutas podadas + regla) · 6.3 Metodología, fuentes de datos y limitaciones (frescura de las fuentes de datos, configuración de la ejecución, declaración explícita de lo que fad-checker no evalúa) |
| Riesgo de cadena de suministro (transversal) | OSV MAL-… + heurística de nombres | Paquetes conocidos como maliciosos (siempre bloquean el control de CI, cualquier nivel de --fail-on) y posibles typosquats (--typosquat: un nombre de npm/PyPI a una edición de distancia de un paquete popular; lodahs↔lodash) |