必须配置 gosec -no-fail=false -severity=high,critical ./... 使其在发现高危漏洞时自动 exit 1,禁止用 -exclude 或 || true 绕过,且需与 go test 分离为独立安全扫描阶段。

直接拦截:只要 gosec 扫描出中高危问题(CRITICAL / HIGH),CI 流水线就必须失败,不能靠人工“再看看”。这是底线,不是可选项。
用 gosec -fmt=sarif + 自定义 exit code 控制流水线成败
gosec 默认只输出报告,不返回错误码——这意味着即使扫出 SQL injection 或 hardcoded credentials,CI 仍会绿灯通过。必须显式让它在发现问题时退出非零码。
- 别用
gosec ./...直接跑:它默认成功退出(exit 0),无论有没有漏洞 - 改用
gosec -fmt=sarif -out=gosec.sarif ./...生成 SARIF,再配合jq判断是否有critical或high级别结果 - 更稳妥的做法是加
-no-fail反向控制:gosec -no-fail=false -severity=HIGH,CRITICAL ./...—— 这个参数会让它在命中任一指定等级时自动exit 1 - 注意
-severity是大小写敏感的,必须全大写;LOW和MEDIUM不会触发失败,除非你明确加上
绕过 false positive 要用 // gosec 注释,别删规则或关全局
遇到误报(比如自研加密库被标 G401),常见错误是直接在 CI 脚本里加 -exclude=G401,这等于对所有代码关掉该检查。真有漏报就全项目裸奔。
- 精准抑制只在具体行加注释:
// gosec:ignore G401(放在被扫描行上方) - 若需忽略整个函数,用
// gosec:ignore G402放在func关键字前一行 -
gosec会识别这些注释并跳过,但 SARIF 报告里仍会记录为 “suppressed”,审计可追溯 - 禁止在 CI 命令里用
-exclude或-skip,那属于策略降级,不是问题处理
流水线里要区分 gosec 和 go test,别混成一个阶段
把 gosec 和 go test 合在一个 step 里跑,看似省事,实则掩盖问题:测试失败时你不知道是单元测试挂了,还是安全扫描卡住了;日志也挤在一起难定位。
- 拆成两个独立 job 或 stage:
test和security-scan,各自有明确命名和超时设置 -
security-scan阶段必须设timeout: 5m(gosec对大型模块可能卡住,尤其启用了-audit) - 确保
security-scan在go mod download之后、go build之前运行——它依赖本地go.sum和 vendor 状态,否则可能漏扫间接依赖 - 别在
gosec命令后加|| true或set +e,那是放弃拦截
真正难的不是让 gosec 跑起来,而是守住「发现 HIGH+ 就必须阻断」这条线。很多人加了扫描却没配 -no-fail=false,或者用 -exclude 图省事,结果流水线永远绿着,漏洞照进不误。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











