composer audit 不能单独使用,它仅基于 composer.lock 中精确版本比对 Packagist 官方 advisories 数据库,不读 vendor/、不看 composer.json、不扫描代码,且跳过 dev 分支、私有包(未配置 security-advisories 源时)及 low 级漏洞;其有效性依赖 lock 文件真实性、源配置合规性及 CI 全链路一致性。

composer audit 不能单独用,它只是工具链里最靠后的一环;真正起作用的是 lock 文件 + audit + 检查策略的组合。
composer audit 命令本身能查什么、不能查什么
它只查 composer.lock 里记录的每个包名和版本,去 Packagist 的 /advisories 接口比对已公开披露的 CVE。不读 vendor/,不看 composer.json,也不扫描代码逻辑漏洞。
- 查不到 dev 分支版本(如
"dev-main"或"dev-develop"),audit 主动跳过 - 查不到私有包,除非你在
repositories里显式配置了含security-advisories字段的镜像源 - 查不到低危(
low)级别漏洞,默认返回非零退出码,CI 卡住是常态 - 如果
composer.lock是空的、被.gitignore忽略、或删了重装生成,audit 结果完全失效
为什么光跑 composer audit 还不够
audit 只回答“这个版本有没有已知 CVE”,但不保证你装的就是这个版本——这取决于 composer.lock 是否真实、是否被 CI 正确使用。
-
composer install没带--no-dev,lock 里混入开发依赖,audit 会扫一堆测试工具的漏洞,干扰判断 - 团队没统一
composer.lock提交规范,有人 git commit -a 把 lock 漏了,CI 节点各自解析,装出不同小版本 - 项目用了
composer-merge-plugin或composer-patches,但没在 CI 中复现 patch 应用过程,lock 文件实际内容与运行时不一致 - PHP 版本约束写成
"php": "^8.0",但 CI 环境是 8.1,某些包的扩展要求(如ext-gmp)在 lock 里没体现,audit 不报,运行时报错
哪些工具能补上 audit 的缺口
单靠 audit 是守不住依赖防线的,得靠其他工具提前卡位:
-
composer-unused:扫出require里写了但代码里根本没use或new的包,减少攻击面 -
composer-require-checker:验证composer.json里声明的扩展(如ext-curl)是否真在运行环境可用,避免“装得上跑不了” -
composer-normalize:统一composer.json格式,防止因字段顺序、缩进、注释导致 diff 冲突,间接保障 lock 文件更新可追溯 -
satis或private packagist:给私有包加security-advisories元数据,让 audit 能扫进去
CI 中怎么串联才不漏掉关键环节
最容易被跳过的其实是 lock 文件的生成时机和内容校验:
- CI 第一步不是
composer install,而是composer validate+composer show --locked --format=json | jq '.packages | length'确认 lock 非空 - audit 必须加
--severity=critical,high --no-dev,否则默认连low都报错退出 - 私有包仓库必须在
composer.json的repositories里声明,并确保该源支持/advisories接口(阿里云镜像不支持,得换源或自建) - 如果项目用了
platform-check或config.platform,audit 前要确认这些配置没掩盖真实的 PHP 或扩展版本
真正难的不是选哪个工具,而是让 lock 文件从开发机到 CI 到部署环境全程“没被悄悄改过”。audit 只是最后一道门禁,钥匙早就在前几道关卡里配好了。


















