composer audit需加--no-interaction --all --format=json并指定绝对路径与--working-dir;应解析json中vulnerabilities数组而非依赖退出码;高危漏洞须在ci中用--fail-on=high拦截,非仅靠cron每日扫描。

Composer audit 命令本身不支持自动报告或静默失败退出
直接在 crontab 里跑 composer audit 很可能“看似执行了,其实没效果”——它默认只在有高危漏洞时才返回非零退出码,且输出内容混杂(含 ANSI 颜色、提示语),不适合管道解析或邮件通知。更关键的是:composer audit 默认只检查当前项目依赖,不会递归扫描 vendor 下所有已安装包的子依赖漏洞(除非加 --all)。
实操建议:
- 必须加
--no-interaction --format=json,否则交互式提示会卡住 cron; - 加上
--all才能覆盖 transitive dependencies(比如你没直连guzzlehttp/guzzle,但它被某个包引入了,也会被扫到); - 别依赖退出码判断“有没有漏洞”,而应解析 JSON 输出里的
vulnerabilities数组长度——因为中低危漏洞不会让命令失败; - 避免用
composer global audit,global 的 vendor 路径不稳定,且权限常导致扫描失败。
crontab 中执行前必须显式指定 PHP 和 Composer 路径
系统级 cron 环境变量极简,which composer 或 php 很可能找不到。硬编码路径最稳,尤其是当项目用 phpbrew、asdf 或自定义 bin 目录时。
实操建议:
- 先在目标用户下运行
readlink -f $(which composer)和readlink -f $(which php)拿到绝对路径; - 在 crontab 里写成:
0 3 * * * /usr/bin/php /usr/local/bin/composer --working-dir=/var/www/myapp audit --no-interaction --all --format=json > /tmp/composer-audit-$(date +\%F).json 2>&1; - 务必加
--working-dir,否则audit会从 cron 当前目录(通常是/root或/home/user)开始找composer.json,大概率报错No composer.json found; - 别用
~或$HOME,cron 不展开这些。
如何把 audit 结果转成可读告警(比如发邮件或写日志)
JSON 输出本身没法直接看,但也不必写完整脚本——用 jq 就够了。重点不是“有没有漏洞”,而是“有没有新增/升级后暴露的新漏洞”。
实操建议:
- 用
jq 'length == 0 or (.vulnerabilities | length == 0)' /tmp/composer-audit-2024-06-01.json判断是否“干净”; - 想快速提取高危项:
jq -r '.vulnerabilities[] | select(.severity == "critical" or .severity == "high") | "\(.package) \(.title) (\(.severity))"' /tmp/composer-audit-*.json; - 发邮件别用
mail -s硬塞 JSON,而是生成摘要文本,例如:echo "Found $(jq '.vulnerabilities | length' /tmp/...json) vulns, $(jq '[.vulnerabilities[] | select(.severity=="high" or .severity=="critical")] | length' /tmp/...json) high/critical" | mail -s "Composer Audit Report" admin@example.com; - 每天覆盖写同一个文件名(如
audit-latest.json),方便对比脚本查 delta。
audit 不是实时防护,它只反映当前 lock 文件状态
哪怕每天扫出 0 个漏洞,只要没人运行 composer update 或没做依赖升级,老漏洞就一直存在。反过来,如果某天突然扫出一堆新漏洞,大概率是最近合并了含新依赖的 PR,或者上游包发布了带漏洞的新版本(而你的 lock 还没更新)。
真正要卡住的环节是 CI 流程:composer audit --no-interaction --all --fail-on=high 应该作为 pre-commit 或 PR check 运行,而不是只靠 daily cron 补漏。
容易忽略的一点:composer audit 查的是 packagist.org 的安全公告数据库,不是本地 CVE 扫描器。它不检测代码层逻辑漏洞(比如反序列化利用),只覆盖官方收录的已知包级漏洞。如果你用 fork 或私有包,它们不会出现在审计结果里。











