pip-audit是最省事的当前环境漏洞扫描工具,它直接读取site-packages中所有已安装包,实时比对PyPI和OSV漏洞数据库,无需requirements.txt即可输出含CVE编号、影响版本及描述的清晰报告。

直接用 pip-audit 扫当前环境,最省事
如果你只是想快速知道现在这个 Python 环境里装了哪些带已知漏洞的包,pip-audit 是最直接的选择。它不依赖 requirements.txt,而是直接读取 site-packages 下所有已安装包,实时比对 PyPI 官方漏洞数据库(PYSEC)和 OSV 数据库。
执行这三行就能得到清晰结果:
pip install pip-audit pip-audit --format columns # 或加 -r requirements.txt 限定范围
-
pip-audit默认递归扫描所有传递依赖,safety不做这事 —— 这是它快且准的关键 - 输出里带 ⚠️ 的条目就是确认存在的漏洞,含 CVE 编号、影响版本范围和描述
- 如果项目用了
pyproject.toml但没生成requirements.txt,pip-audit仍能扫,safety会报错退出 - 注意:它不检查 setup.py 里恶意执行代码、不分析源码逻辑漏洞,只管“已公开披露的已知漏洞”
safety check -r 要配 --full-report,否则等于白跑
safety 只认 requirements.txt(或 constraints.txt),而且默认输出极度简略 —— 漏掉 CVE 编号、受影响版本区间、修复建议,根本没法判断要不要升级。
必须加 --full-report 才有用:
safety check -r requirements.txt --full-report
- 不加
--full-report时,insecure条目只显示包名和“高危”,你不知道是哪个 CVE、是否已在新版修复 -
unpinned(如requests)默认不报,要显式加--ignore-unpinned才提示版本未锁定风险 -
safety的数据库(safety-db)更新有延迟,低危漏洞可能滞后数天;高危通常几小时内同步 - CI 环境里若网络受限,得换离线模式:
safety check -r req.txt --db https://raw.githubusercontent.com/pyupio/safety-db/master/data/insecure.json
别信 pip freeze > req.txt,先清理再扫
很多人的 requirements.txt 是用 pip freeze > requirements.txt 直接导出的,里面混着开发依赖、临时调试包、甚至废弃不用的旧包 —— 扫出来的“漏洞”八成是噪音。
- 真正要扫的,应该是部署时实际需要的最小依赖集,不是你本地环境全量
- 用
pipreqs . --force基于源码 import 推断依赖,更贴近真实使用面(但它不解析pyproject.toml中的依赖声明) - 更稳妥的做法:在干净虚拟环境中重装生产依赖,再
pip freeze > requirements.txt - 手动删掉
dev类 extras(如pytest,black),它们不该进生产扫描范围
CI/CD 里扫出漏洞后,别直接 fail
CI 流水线里 pip-audit 或 safety 返回非零退出码,默认会中断构建 —— 这容易把“中危但暂无修复版”的包当成阻塞项,反而掩盖真正该紧急处理的高危问题。
- 用
--fail-on=CRITICAL(safety)或--exit-code(pip-audit)精准控制中断阈值 - 允许中低危继续通过,但把报告存为 artifact,人工跟进
- 避免缓存干扰:CI 中加
--cache-clear(safety)或指定--cache-dir(pip-audit) - 记住:工具只告诉你“这里有问题”,不告诉你“怎么修”。CVE 描述里的 “Fixed in version X.Y.Z” 才是关键动作点
真正麻烦的从来不是扫不出来,而是扫出来一堆“无法升级”的包 —— 比如某个老项目卡在 Django 2.2,而它的某个子依赖已被标记为高危,但新版本 Django 已不兼容。这种时候,光靠工具没用,得人工拆解依赖树、找替代方案、甚至补丁临时修复。











