govulncheck默认仅扫描直接依赖,需加-test参数才能覆盖测试文件中引入的间接依赖;go list -m all配合人工核查是必要补充,go mod verify和gosec等工具须协同使用以弥补漏洞漏检风险。

govulncheck 必须加 -test 才能扫到间接依赖
默认 govulncheck ./ 只分析你项目里 go.mod 中显式 require 的包,但真实漏洞常藏在 // indirect 依赖里——比如某个日志库悄悄拉进来的 golang.org/x/net,不加 -test 就根本不会被分析。
实际操作要跑两遍:
-
govulncheck ./:覆盖业务代码路径,检查直接依赖调用链 -
govulncheck -test ./:加载测试文件(*_test.go)里的 import,触发更多 transitive 依赖的 callgraph 分析
注意:如果项目没写测试,-test 也扫不到对应路径;但只要写了测试且用了高危包(如 github.com/gorilla/mux),它大概率会被拉进来并暴露问题。
go list -m all 是人工盯包的底线手段
govulncheck 会跳过 test-only 依赖,而有些包只在测试里用、线上不用,却仍会被 go mod download 下载——比如 golang.org/x/crypto 在测试中做 mock 加密,但它本身有已知漏洞,govulncheck 不报,go.sum 也不拦。
必须定期手动查一遍:
go list -m all | grep -E "(golang\.org/x|github\.com/.*\.(sql|http|crypto))"- 对每个匹配项,再执行
go mod graph | grep 包名看谁引入了它 - 重点盯
golang.org/x/net和golang.org/x/text:它们被标准库周边大量间接依赖,但govulncheck的 callgraph 分析不一定覆盖全部子功能
go mod verify 不是可选项,是 CI 第一行就该跑的门禁
go.sum 只保证“和上次构建用的依赖一模一样”,不保证第一次下载的就是干净的。尤其当你设了 GOPROXY=fallback 或用了私有 proxy,中间人可能替换模块内容。
CI 中必须强制启用远程校验:
- 设置环境变量:
GOSUMDB=sum.golang.org(别信旧版 Go 默认值,某些版本默认关掉) -
go mod verify要放在 CI 流水线最开头,失败直接中断 -
go.sum文件必须提交 Git,每次go mod tidy后人工确认新增条目来源——比如突然冒出个github.com/xxx/yyy@v0.0.1,得查它是不是内部库
别把 govulncheck 当最终答案
输出 "no vulnerabilities found" ≠ 安全。可能只是当前调用路径没进分析范围,或漏洞还没被收录进 vuln.go.dev 数据库(GO-XXXX-XXX 编号不是 CVE,不能拿去搜 NVD)。
真正容易被忽略的是:一个二级间接依赖里某个冷门函数(比如 encoding/xml.Unmarshal 的特定用法)可能触发已知漏洞,但 govulncheck 因为没走到那条调用路径就完全漏掉。所以扫描必须配合 gosec 做代码级审计,再加 go vet -vettool=$(which staticcheck) 检查不安全的 API 使用。

















