Formidable Auditor's Dependency Checker
又名 Fuckin' Autonomous Dependency Checker
fad-checker 可审计任意源码树中的 Maven · Gradle · npm · Yarn · pnpm · Composer · PyPI · NuGet · Go · Ruby、vendored JavaScript、已提交的原生二进制文件以及加密材料(证书与私钥/公钥);支持多模块、monorepo、多语言;并生成自包含的 HTML + Word 报告(CVE 按 EPSS + CISA KEV 优先级排序,包含 EOL、过时、过期、许可证信息),以及 CycloneDX SBOM / CSAF VEX / SARIF / JSON 导出。无需构建工具、无需 Docker、无需网络;它直接从磁盘读取 lockfile 和 manifest。

mvn/gradle/npm install/pip/dotnet restore/go build,无需 node_modules/。Maven 依赖图按 Maven 自身的方式解析。→ 原理--offline 下零网络,经过回归测试,并可在 unshare -rn 下复现。在 Maven 上,它在完全没有网络接口的情况下恢复了 OSV-Scanner 在线 结果的 657/657,而其他工具分别为 45 / 40 / 37。→ · 📖 用法与所有标志 · 架构 · 与其他工具对比 · 数据源
它在审计中能做到而其他工具做不到的事。列集与数据来源规范与
docs/COMPARISON.md 相同 —— ⚠️ 表示 部分支持 并说明方式,各单元格应可核查。
¹ 无需 mvn/go/npm/pip/dotnet —— manifest 直接从磁盘解析,不安装也不执行任何东西。一次扫描 105 个 pom.xml:790 对依赖 vs OSV-Scanner 的 657,133 个为 fad 独有,版本按 每个模块 调解而非扁平化。
² 在 unshare -rn 下,无网络接口,恢复 OSV-Scanner 在线 Maven 结果的 657/657。经过绊线测试;只有公共坐标会离开隔离区。
³ 第 0 章列出 每个 已配置仓库都返回 404 的每个坐标 —— Maven、npm、PyPI、NuGet、Composer、Go 和 RubyGems —— 并附上声明它的 manifest。超时或出错的仓库从不计入:否则一个不确定的答案会因客户代理不稳定而指控其发布了内部包。随后可用 -e <regex> 排除它们。
⁴ -t <dir>:规范化 POM 以及所有非 Maven lockfile 的镜像,剥离私有坐标。可归档,且可被任何工具扫描 —— 包括 --snyk。
⁵ endoflife.date,区分 直接 vs 传递,让你知道该升级哪个依赖,外加已弃用/已废弃/已撤回和过期。Trivy 仅覆盖 OS 发行版;Snyk 的包健康度仅限 Web。
⁶ 清单 和 判定:过期、RSA<2048、MD5/SHA1、自签名;私钥 vs 公钥;JKS/PKCS#12。离线解析器。Trivy 的密钥规则找到的是文件,而非缺陷。
⁷ 通过 deps.dev + CIRCL 以 哈希 识别 → 应声明 / 名称≠校验和 / 未知 / 恶意。Syft 的模式匹配命名的是版本,而非身份。
⁸ 第 0 章标记 本次 扫描无法触及的内容(缺失 lockfile、仅 BOM 版本、Yarn Berry、无法确定的 PHP 运行时);第 6.3 章说明该工具从不评估的内容。在其他工具中,前者是审计从未看到的日志行,后者根本没有写下来。
⁹ 溯源清单:全部 13 个数据源 的工具、运行时、模式、运行配置和缓存新鲜度。Grype 和 Dependency-Check 只携带一个数据源的日期,而非本次运行。
¹⁰ 第 0→6 章,含执行摘要和修复配方,自包含 HTML 外加 Word .doc 副本。其他工具都不输出 Word。
¹¹ 四个内联 SVG 图表 —— 按最严重程度划分的 CWE、每个根依赖的易受攻击传递依赖、最易受攻击的模块(单模块项目上直接 vs 传递)、修复优先级分带 —— 也会渲染到 .doc 中,一键复制为 PNG(或表格为富 HTML),粘贴到 Word 时保持格式。每个 CVE 都保留其 CVSS 向量、CWE、参考、CPE 配置和 via-path,位于下钻之后,零外部资源。
¹² --baseline 添加 Δ 章节(新增 / 已修复 / 未变);--fail-on-new 仅针对新增发现设置门禁。Snyk 在其平台上跟踪此功能,而非作为本地差异。
它的短板 —— 容器/OS 包、自动修复 PR,以及相对于 Snyk 精选 feed 的 CVE 覆盖 → docs/COMPARISON.md ·
差距实测。
刻意不设为目标:可达性。 一个发现就是依赖图上的易受攻击版本,报告如实说明这一点(第 6.3 章),而非猜测调用路径。判断易受攻击的代码在 此 应用中是否可达,是审计人员的决定,需借助任何扫描器都没有的应用上下文。
[!WARNING] fad-checker 是新项目,可能仍包含(罕见的)bug。请将其输出视为强有力的第一遍结果,对任何关键内容进行复核,并请 报告问题;它们会被快速修复。
npm install -g fad-checker fad-checker -s ./my-project # → ./fad-checker-report/cve-report.html
一个免费的 [NVD API 密钥](https://nvd.nist.gov/developers/request-an-api-key)(即时获取)可将富化速度提升 10 倍:`fad-checker --set-nvd-key YOUR_KEY`。以下是一些常用运行方式;完整列表可通过 `fad-checker --help` 或 [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
-t <dir> 实际做了什么。 这是一个提取步骤,而不是 Snyk 适配器。它会写出一个
规范化依赖描述符的平行目录树:每个 pom.xml 被缩减为与依赖相关的节点(坐标、properties、dependencyManagement、dependencies、
modules),reactor 父级被重新连接到它们在树中真实的 relativePath,坐标中的 ${…} 被解析——外加每个非 Maven 锁文件/清单文件被镜像到相同的相对路径
(package-lock/yarn.lock/pnpm-lock、composer.lock、poetry/Pipfile//、
/、/、,以及诸如
或 之类的伴随文件)。在线时,它还会,并报告那些在那里不存在的坐标——即你的
——随后 会将这些模块从重写后的 POM 中剥离。然后它
:除非你同时传入 、某个 、
或 ,否则不会进行 CVE/EOL 检查,也不会生成报告。你得到的是一个无需构建、经过净化的依赖清单,你可以
将其归档作为审计证据、交给客户或法律审查,或指向任何扫描器——通过
使用 Snyk 就是其中之一。
[!IMPORTANT]
--offline读取缓存,而不是替代缓存。 在冷缓存上没有任何东西可以 匹配,因此离线首次运行合理地报告 0 CVE / 0 EOL / 0 过时; 那是空缓存,而不是干净的项目。先预热一次(对任何项目进行一次正常的在线运行, 或使用--import-cache),然后--offline就会在零网络调用的情况下返回完整结果集。 气隙机器通过--export-cache/--import-cache获取其缓存。
单个自包含二进制文件(无需 Node)、从源码安装以及 shell 补全见 → docs/USAGE.md。
报告按根章节组织(每个章节将相关的子章节分组):
HTML 报告可在任何浏览器中打开,包含所有细节(CVSS 向量、参考、完整描述、CPE 配置、传递依赖的经由路径),并附带一个 Word 兼容的 .doc 副本。每个匹配项都带有复合优先级(KEV 已被利用 > EPSS 可能性 > CVSS 严重性),并且运行还可以额外生成 CycloneDX 1.6 SBOM(--report-sbom,漏洞内联)和 CSAF 2.0 VEX(--report-csaf)以供下游工具使用。

没有工具能发现一切。fad-checker 在 908 对并集中的 87% 上领先,并且有 131 对来自 Snyk 而非它。逐一对照 OSV 裁定后,没有一个是召回缺陷:
三分之二与公开记录相矛盾,因此报告它们将意味着发布误报。CVE-2023-6481 是清晰的例子:声称影响 [email protected],它绑定的是 [1.2.12, 1.2.13) 的 logback-core——错误的制品,而且该版本在该缺陷存在之前就已发布。
范围。 所有 131 个都是 Snyk 的:OSV-Scanner、Trivy 和 Grype+Syft 各自贡献了 0 个其他人没有的发现。而且全部都在 Maven 目标上——在 Maven 之外,依赖图就在锁文件中,每个扫描器读取相同的输入,基准测试在 npm、RubyGems 和 Composer 上测量到相同的发现集。
这就是 --snyk 存在的原因。 fad-checker 将 snyk test 输出作为输入并合并它,因此你得到的是并集,而不是选边站。这是一个覆盖范围的选择,而不是更正。
方法、注意事项和逐对裁定 → docs/BENCHMARK.md;使用 scripts/adjudicate-gap.js 复现。
零数据发送保证。 在
--offline下,fad-checker 完全不进行任何网络调用;它只读取已预热的~/.fad-checker/缓存,绝不将依赖、路径或发现传输到机器之外。它经过回归测试 (test/offline-guarantee.test.js,一个被触碰就会抛出的绊线获取器),并且审计员可复现:unshare -rn node fad-checker.js -s ./proj --offline …在一个没有网络接口的命名空间中运行它,并产生字节完全相同的发现。与主流 OSS 扫描器不同,fad 还能离线解析 Maven 传递依赖图;因此在一个气隙多模块项目上,它能发现它们无法发现的传递 CVE。
当被审计系统离线 / 机密时(受监管或气隙审计的典型情况),它 无法访问 OSV / NVD / Maven Central / npm。将工作拆分到多台机器上,同时保持 零环境信息离开安全飞地:匿名化描述符仅携带 公共包坐标;没有文件系统路径、没有注册表 URL、没有 主机名/用户名;并且详细报告在离线机器上生成。
传输依赖于 fad-checker 缓存的一个特性:它们以坐标 或漏洞 id 为键,从不以路径为键,因此它们是机器无关的。在线步骤只是 预热缓存;离线步骤重放扫描并获得缓存命中。```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
描述符(`fad-deps/1`)包含与丢弃的内容对比:
| 保留(扫描所需) | 丢弃(环境相关) |
| --- | --- |
| ecosystem、ecosystemType | manifest 路径 / pom 路径 |
| namespace、name | 解析后的 registry URL |
| version、versions | 完整性哈希 |
| scope、isDev | 父链、lockfile 类型 |
在线阶段报告本身不含路径;vendored-JavaScript(retire.js)的发现结果是在**阶段 3 离线生成**的,因为 retire 需要实际的 `.js` 文件;其签名数据库在线预热(阶段 2),并通过 `--export-cache` 携带。完整的离线/缓存控制 → [`docs/USAGE.md`](https://github.com/9pings/fad-checker/blob/main/docs/USAGE.md)。
## 文档
- [`docs/USAGE.md`](https://github.com/9pings/fad-checker/blob/main/docs/USAGE.md);每个标志和工作流:离线/缓存控制、私有 registry、配置文件、配方、安全护栏。
- [`docs/ARCHITECTURE.md`](https://github.com/9pings/fad-checker/blob/main/docs/ARCHITECTURE.md);内部实现:编解码器、收集、匹配、报告流水线。
- [`docs/COMPARISON.md`](https://github.com/9pings/fad-checker/blob/main/docs/COMPARISON.md);与 OSV-Scanner / Trivy / Grype / OWASP DC / Snyk 的对比,以及它如何保持无需构建。
- [`docs/BENCHMARK.md`](https://github.com/9pings/fad-checker/blob/main/docs/BENCHMARK.md) — 在公开的 105 模块项目上,与 OSV-Scanner 对比的可复现气隙召回率基准测试。
- [`docs/DATA-SOURCES.md`](https://github.com/9pings/fad-checker/blob/main/docs/DATA-SOURCES.md);fad-checker 使用的公开数据集及其许可证。
- [`docs/SPEC-audit-pro.md`](https://github.com/9pings/fad-checker/blob/main/docs/SPEC-audit-pro.md);审计级功能(来源追溯、差异审计、方法论/完整性)以及每项功能如此设计的原因。
- [`CHANGELOG.md`](https://github.com/9pings/fad-checker/blob/main/CHANGELOG.md) · [`CLAUDE.md`](https://github.com/9pings/fad-checker/blob/main/CLAUDE.md);发布历史 · 面向贡献者的代码级导引。
## 贡献
对一个年轻的扫描器来说,最有用的贡献是**告诉它哪里出错了**:在真实项目上运行它,并提交一份[误报/漏报报告](https://github.com/9pings/fad-checker/issues/new?template=false_positive.yml),附上产生该结果的坐标和 manifest 片段。开发环境搭建、基本规则和编解码器扩展点 → [`CONTRIBUTING.md`](https://github.com/9pings/fad-checker/blob/main/CONTRIBUTING.md)。fad-checker 自身的漏洞 → [`SECURITY.md`](https://github.com/9pings/fad-checker/blob/main/SECURITY.md)(请私下报告)。
**关于 AI 辅助:** 此代码库在编写过程中大量使用了 Claude Code;仓库根目录下的 [`CLAUDE.md`](https://github.com/9pings/fad-checker/blob/main/CLAUDE.md) 正是它看起来的样子。它所遵循的标准是你可以自行检验的:**847 个测试**(`npm test`)、由绊线测试强制并在 `unshare -rn` 下可复现的零网络保证,以及对照 Snyk 基线而非凭空断言的覆盖率数字。`fad-checker` 本身在运行时**不使用任何 LLM**;发现结果来自公开漏洞数据库和确定性解析器,且不生成任何报告文本。完整声明,包括审查实际捕获到错误发现的地方 → [`AI_POLICY.md`](https://github.com/9pings/fad-checker/blob/main/AI_POLICY.md)。如果代码未达到该标准,那正是我希望收到的 bug 报告。
## 许可证
MIT;见 [`LICENSE`](https://github.com/9pings/fad-checker/blob/main/LICENSE)。
--typosquat)。SHA256SUMS;差分审计 可与先前运行进行对比(--baseline),CI 可仅针对 新增 发现设置门禁。--help;大量开关折叠为四个标志 —— -d eol,nvd 关闭功能,-a licenses,snyk 开启默认关闭的功能,-r html,json 选择输出,-o 指定位置。单独的标志仍然可用,--help-all 会列出它们。--lang fr)--report-doc 时输出 Word .doc),CycloneDX 1.6 SBOM、CSAF 2.0 VEX、SARIF 2.1.0、JSON;用 --fail-on 设置门禁,用 --ignore/--vex 进行分诊。支持每个生态系统的私有仓库。| 审计人员实际需要做的事 | fad | OSV | Trivy | Grype+Syft | OWASP DC | Snyk |
|---|
| 一条命令审计 100 模块的多语言 monorepo,且 无需安装任何工具链 ¹ | ✅ 105 个模块 | ⚠️ 跳过 reactor | ⚠️ 需要 ~/.m2 | ⚠️ 需手动启用 | ⚠️ 需 Java 构建 | ⚠️ 需 mvn 构建 |
| 离线/气隙扫描且不丢失传递依赖 ² | ✅ 657/657 | ❌ | ⚠️ ~/.m2 | ⚠️ 需手动启用 | ⚠️ 需镜像 | ❌ |
| 识别大型项目中的私有/内部依赖 ³ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| 将清理后的依赖描述符提取 到外部目录 ⁴ | ✅ -t | ❌ | ❌ | ❌ | ❌ | ❌ |
| 报告 EOL / 已弃用的框架与依赖,包括传递依赖 ⁵ | ✅ | ⚠️ 仅已弃用 | ⚠️ 仅 OS 发行版 | ❌ | ❌ | ⚠️ 仅 Web UI |
| 报告已提交的密钥与证书 ⁶ | ✅ | ❌ | ⚠️ 密钥规则 | ❌ | ❌ | ❌ |
发现已提交的二进制文件(.dll、.exe 等)并对照其校验和检查 ⁷ | ✅ | ❌ | ⚠️ 部分 | ⚠️ 模式匹配 | ❌ | ❌ |
| 清晰列出 未 扫描的内容 —— 在客户询问之前 ⁸ | ✅ 第 0 章 + 6.3 | ⚠️ 日志 | ⚠️ 日志 | ⚠️ 日志 | ⚠️ 日志 | ⚠️ 日志 |
| 六个月后回答"基于什么数据?" ⁹ | ✅ | ❌ | ❌ | ⚠️ 数据库日期 | ⚠️ NVD 日期 | ❌ |
| 发送报告,而非 JSON 转储 ¹⁰ | ✅ HTML + .doc | ⚠️ HTML 列表 | ⚠️ 模板 | ❌ | ⚠️ HTML 列表 | ⚠️ snyk-to-html |
| 图表、逐 CVE 下钻和可粘贴的 Word 副本 ¹¹ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| 生成仅显示变更内容的增量报告 ¹² | ✅ --baseline | ❌ | ❌ | ❌ | ❌ | ⚠️ 云端 |
uvpdm*.csprojpackages.lock.jsongo.modgo.sumGemfile.lockDirectory.Packages.propsnuget.config-e <regex>--snyk--report-<type>--fail-on*--baseline--snyk| 章节 | 来源 | 它能捕获什么 |
|---|
| 0. 警告 (顶部) | 本地启发式 | 缺失的锁文件、未解析的 Maven 版本(由 BOM 管理)、不在 Maven Central 上的私有库 |
Δ. 自基线以来的变化 (顶部,配合 --baseline) | 与先前 JSON 的差异 | 每个类别的新增 / 已修复 / 未变化发现 + 新增生产环境 CVE 列表;用于重复审计和 --fail-on-new CI 门禁 |
| 1. CVE (X 直接,Y 间接,Z 开发) | CVEProject + OSV.dev + NVD + CPE | 1.1 生产环境;生产依赖中的公共 CVE / GHSA,按生态系统、按清单文件,按 CISA KEV + EPSS + CVSS 优先级排序 · 1.2 内置 JS 漏洞(retire.js) · 1.3 开发(test/provided、dev/optional/peer) · 1.4 可能的误报(经 CPE 过滤) |
| 2. 未管理 / 未版本化的组件 | deps.dev + CIRCL(按校验和)、retire.js、内置 X.509 | 2.1 嵌入式二进制文件;提交的 .jar/.war/.ear 内所附带库中的 CVE(fat-jar、shaded uber-jar) · 2.2 原生二进制文件(.dll/.exe/.so/.dylib)按哈希识别,标记为应被管理 / 名称≠校验和 / 未知 / 恶意 · 2.3 内置 JavaScript 清单(jQuery、Bootstrap 等)无论是否有漏洞 · 2.4 证书与密钥材料;提交的证书(过期 / 弱密钥 / 弱签名 / 自签名)、私钥与公钥(PEM/OpenSSH/PuTTY/PGP/SSH)以及密钥库,全部离线解析 |
| 3. 维护 / 生命周期 (X EOL,Y 过时,Z 落后) | endoflife.date · 精选 + 注册表标志 · Maven Central / npm / Packagist / PyPI / NuGet | 3.1 生命周期终止框架(+ 一个带 --eol-support 的“已脱离主动支持”区间;Symfony/Laravel 按框架合并为一行;当 Composer 约束证明时包含 PHP 运行时),分为直接(声明的 / 父 POM 继承的——升级这些)与传递(升级引入它们的依赖) · 3.2 过时 / 已弃用 / 已废弃 / 已撤回 · 3.3 落后(有更新的版本可用,附发布日期;仅直接依赖) |
4. 许可证 (可选:--licenses) | 注册表元数据 + Maven POM → SPDX 策略 | 每个依赖的许可证被规范化为 SPDX 并分类;copyleft(GPL/AGPL/LGPL/MPL)、专有和未知被标记以供审查 |
| 5. 修复建议 | 计算得出 | 按生态系统的固定配方:Maven <dependencyManagement>、Gradle constraints { }、npm overrides、yarn resolutions、composer require、pip install、dotnet add package |
| 6. 扫描上下文与限制 | 来源清单 + 遍历 | 6.1 已扫描的描述符(每个已解析的清单文件) · 6.2 已忽略的目录(被剪除的路径 + 规则) · 6.3 方法、数据源与限制(数据源新鲜度、运行配置、明确说明 fad-checker 不 评估什么) |
| 供应链风险 (横切) | OSV MAL-… + 名称启发式 | 已知恶意包(始终阻止 CI 门禁,任何 --fail-on 级别)和疑似仿冒域名(--typosquat:与流行包仅一个编辑距离的 npm/PyPI 名称;lodahs↔lodash) |
| 裁定 |
|---|
| 57 | 错误的制品——该公告绑定的是不同的坐标 |
| 31 | 超出范围——该版本位于所有声明的受影响范围之外 |
| 23 | 不在 OSV 中——19 个专有的 SNYK-* id,4 个仅 NVD 收录 |
| 19 | 无 Maven 绑定——该公告根本不绑定任何 Maven 包 |
| 1 | 已报告,以 CVE 别名形式 |
| 0 | 确认遗漏 |