govulncheck 默认只扫描直接依赖,间接依赖必须加 -test 参数;它是 Go 1.21+ 官方唯一内置漏洞扫描工具,但需配合 go list -m all、go mod verify 和 trivy 等多工具协同,才能全面覆盖测试链路、幽灵依赖及供应链风险。

govulncheck 默认只扫直接依赖,间接依赖必须加 -test
govulncheck 是 Go 官方唯一内置的漏洞扫描工具(Go 1.21+),但它默认行为非常保守:govulncheck ./ 只分析你 go.mod 里显式声明的直接依赖,完全跳过测试代码中引入的、或由第三方库拉进来的间接依赖。而真实风险往往藏在 golang.org/x/net、github.com/gorilla/mux 这类被层层传递的包里。
必须补上第二遍扫描:govulncheck -test ./。这个参数会构建测试代码的调用图(callgraph),把 _test.go 文件里用到的所有包都纳入分析范围——很多高危包(比如 golang.org/x/crypto)只在测试中使用,线上不走,但 CI 构建时仍会下载,govulncheck 不加 -test 就直接忽略它们。
- 输出里的
GO-XXXX-XXX是 Go 官方编号,查 vuln.go.dev,不是 CVE,别去 NVD 搜 -
no vulnerabilities found不等于安全:可能调用路径没进 callgraph,或漏洞尚未收录进数据库 - 想导出结构化结果用于 CI 判断?加
-json参数,但注意:它总返回 exit code 0,得自己解析 JSON 里的Vulnerabilities字段长度
trivy 扫 Go 项目比 govulncheck 更全,但需注意模式选择
trivy 不是 Go 原生工具,但对 Go 项目的覆盖更“暴力”:它不依赖调用图分析,而是直接解析 go.sum 和 go list -m all 输出,把所有出现在依赖树里的模块都拿去比对 CVE 数据库。这意味着它能发现 govulncheck 因路径未触发而漏掉的漏洞。
关键在命令模式:
立即学习“go语言免费学习笔记(深入)”;
- 扫源码依赖(推荐 CI 阶段用):
trivy fs --security-checks vuln --severity HIGH,CRITICAL ./ - 扫已编译二进制(适合发布前验证):
trivy binary --security-checks vuln myapp - 别用
trivy repo扫 Git 仓库——它只看go.mod,和govulncheck ./一样漏间接依赖
trivy 的缺点是误报略多(比如某个包有 CVE,但你根本没调用相关函数),但它至少不会“假装安全”。遇到可疑结果,再用 govulncheck -test 确认是否真被调用。
go list -m all + 人工盯包,是发现“幽灵依赖”的唯一可靠方式
有些包根本不在 govulncheck 或 trivy 的扫描范围内:比如只在 test 目录下 import、或通过 replace 引入的私有 fork 分支。这些包不会出现在标准漏洞数据库里,但可能被篡改、含后门、或作者已弃坑。
执行:go list -m all | grep -E "(golang\.org/x|github\.com/.*\.(sql|http|crypto|jwt))",手动翻一遍列表。对每个可疑模块:
- 查它的
go.mod是否标记// indirect—— 如果是,说明没人直接 require 它,纯靠传递引入,风险更高 - 用
go mod graph | grep 包名看谁把它拉进来,判断能否移除 - 访问 pkg.go.dev 页面,重点看 “Last updated” 时间、Open issues 数量、是否有近 6 个月内的 commit
特别留意 golang.org/x/text 和 golang.org/x/net:它们被上百个主流库依赖,但官方漏洞库对它们子功能的覆盖不全,必须人工核对更新日志。
go mod verify 必须进 CI,且不能只信 go.sum
go.sum 不是防篡改的保险栓,它只保证“和上次构建用的依赖一模一样”,不保证第一次下载的就是干净的。如果你本地配置了 GOPROXY=direct 或用了不靠谱的私有 proxy,go mod download 可能悄悄拉下被污染的模块。
CI 流水线第一行就得跑:go mod verify。它会连接 sum.golang.org 公共日志,校验每个模块哈希是否被官方记录过。失败就中断,不给机会。
- 强制启用远程校验:
GOSUMDB=sum.golang.org,别依赖旧版 Go 的默认关闭行为 -
go.sum文件必须提交 Git,每次go mod tidy后要人工确认新增条目——比如突然多了个github.com/xxx/yyy@v0.0.1,得查清楚是不是你团队内部库 - 别删
go.sum或加// skip注释绕过校验,这是供应链攻击最常利用的缺口
真正难的不是工具怎么用,而是接受一个事实:Go 的模块机制天然允许“看不见的依赖”存在。扫完工具报告只是起点,go list -m all 输出里每一行,都得有人看过、问过、信过。


















