这四个工具里有两个能阻止一把密钥进入仓库;另外两个只能告诉你它已经进去了。既然「一把泄漏凭据被利用」已经被观测到能在五分钟内完成,这个区别就决定了结果——而藏在它底下更难的那个问题,不是哪个工具检出得更多,而是哪个工具的失败你看得见。
一览
下面的数字取自各项目自己的文档,截至 2026 年 11 月。
| 工具 | 站位 | 价格或许可 | 校验是否仍有效 |
|---|---|---|---|
| GitHub Secret Protection | 服务端推送保护,加仓库扫描 | 每位活跃提交者每月 19 美元;公开仓库上推送保护免费 | 有——有效性检查(Team 与 Enterprise) |
| GitLab 密钥推送保护 | pre-receive 钩子;自 GitLab 17.5 起 GA | Ultimate 档 | 无 |
| TruffleHog | 检测器;pre-commit 钩子与定时扫描 | 自 v3 起为 AGPL-3.0 | 有——verified、unverified、unknown |
| Gitleaks | 检测器;pre-commit 钩子与 CI | MIT | 无 |
GitHub Secret Protection
你实际买到的是什么
GitHub 把 Advanced Security 拆了包,Secret Protection 现在是一个独立 SKU,每位活跃提交者每月 19 美元,而 Code Security 另行定价 30 美元。按提交者而不是按席位计费,比听起来更要紧:只读账号与休眠用户不计费,所以账单追踪的正是那群真能造成暴露的人。
在公开仓库上,推送保护、密钥扫描、提供方模式与提供方通知都是免费的。对多数组织来说,这是手上杠杆最高的一次配置改动,而且它覆盖的正是攻击者会去查询的那个群体——微软 11 月那份报告描述的,就是智能体在搜索公开的 GitHub 以寻找客户端密钥。
付费线划在哪里
付费档是覆盖范围越过「已知提供方格式」的地方。有效性检查——去问签发提供方这把令牌是否还能用——属于 Team 与 Enterprise。通用模式(未知提供方的令牌、连接字符串、私钥)与「用于告警的 AI 检出密钥」也是,而后者正是像明文口令这种非结构化凭据能被找到的唯一途径。「推送保护里的 AI 检出密钥」又是另一回事:它处于预览阶段,并会消耗 AI Credits。
请仔细读这个分层,因为它意味着免费档拦的是「有可识别形状」的东西,而付费档拦的是没有形状的东西。一个内嵌了口令的数据库连接字符串,既是真实泄漏的原型,也是「非结构化」的原型。
GitLab 密钥推送保护
一道边界被公开的门禁
GitLab 的对应物运行在 pre-receive 钩子里:你推送,服务器在接受写入之前检查。它在 GitLab 16.7 作为实验特性出现,17.1 进入 Beta,并在 17.5 达到正式可用;自 17.11 起它扫描 diff 而不是整个文件。它需要 Ultimate 档。
让它成为这四者中最便于推理的那一个的,是它的例外被写成了数字。密钥推送保护会在以下情况下被跳过:
- 文件或 diff 补丁大于 1 MiB;
- 一次推送改动超过 3,150 个路径,或超过 350,000 行;
- 规则集解析或编译失败,或扫描收到了无效输入。
而它也可以被刻意跳过:在推送时附上 -o secret_push_protection.skip_all,或者在某条提交信息里写上 [skip secret push protection]。两者都会产生审计事件,而自 17.9 起,审计事件会记下是哪些提交跳过了这项检查。
那张清单不是在披露弱点——它就是这项特性本身。一道绕过条件被写成阈值公开出来的门禁,是一道你能监控的门禁:为那条审计事件设告警,也为跨过 3,150 个路径的推送设告警。而一道例外未被公开的门禁,有同样的洞,却没有告警。
TruffleHog
检测是便宜的那一半;校验是稀缺的那一半
TruffleHog 什么也不拒绝。它没有服务端门禁,而它的 README 记录了一个 pre-commit 钩子、却没有 pre-receive 钩子。它拥有的,是免费替代品里没有谁提供的那项能力:它拿起一把候选凭据,去问签发服务它是否还能用,并返回三种状态之一——verified(已确认有效)、unverified(检出了,未确认,也可能已失效)、unknown(校验本身失败了,通常是网络或 API 错误)。--results=verified 会把输出收窄到已确认有效的密钥。
这个三态结果是值得偷走的设计细节。大多数工具把「我们查了,它已经死了」与「我们没查」塞进同一个桶,而这恰恰是一个分诊队列所需要的区分。把 unknown 单独留着,是对一次失败的检查的诚实承认,而不是一次静默降级——这与一次 结构化拒绝 的纪律相同。
范围,以及许可这个问题
覆盖面很广——README 声称有 700 多个带主动校验的凭据检测器,并对 800 多种密钥类型做分类——而它触达的范围超出 git:文件系统、S3、GCS、Docker 镜像、stdin、Postman、Jenkins、Elasticsearch、Hugging Face、CircleCI、Travis、syslog 与 GitLab。analyze 子命令走得更远,会把一把凭据能触达什么画出来,但只覆盖大约二十种最常泄漏的类型,所以请把它当成针对大提供方的分诊加速器,而不是一项通用能力。
许可自 v3 起是 AGPL-3.0(v3 之前的代码仍为 GPL-2.0)。在你自己组织内部的 CI 里使用,这不值一提;但如果你打算把它嵌进一个你对外发行或托管的产品里,那是一场法务对话,而不是技术对话。
Gitleaks
快、MIT,而且不再往前走了
Gitleaks 是多数团队已经装了的那一个:MIT 许可、快、作为 pre-commit 钩子或 GitHub Action 都能轻松装上,默认的 config/gitleaks.toml 里有 222 条规则。当前的模式是 git、dir 与 stdin;detect 与 protect 自 v8.19.0 起已废弃。
决定它是否还该当你主检测器的那个事实,就写在 README 里:「Gitleaks 功能已完备。我不会再把新特性合进 Gitleaks。未来的发布只会是安全补丁。」维护者已经转向一个后继项目 Betterleaks。
这是一句关于你明年覆盖面的陈述,而不是关于今天这份代码质量的陈述。新的凭据格式在持续出现——每一家推出 API 的提供方都在铸造一种新的令牌形状——而一套被冻结的规则集不会把它们学过来。一个检测器的价值,正以「生态系统签发新密钥格式的速度」衰减,而那个速度并没有放慢。
要盯的是那个基线
Gitleaks 的基线工作流——先用 --report-path 扫一次,再把那份报告用 --baseline-path 传回去,于是只看到新发现——对于在一个老仓库上落地这个工具而不被 4,000 条告警淹没,是真有用的。它同时也是让真实泄漏变得永久隐形的那个机制:基线里的一切,按定义永远不会再被报告一次,而基线里没有任何东西被校验过「是否已失效」。同样的道理适用于 README 标注为实验性的 .gitleaksignore,以及行内的 gitleaks:allow 注释。
如果你当初带着一份基线落地了 Gitleaks,而之后再没回头看,那么你的仓库里有一份未经复核的「候选有效凭据」清单。请把 TruffleHog 的校验在那些基线条目上跑一次。返回 verified 的那些,不是历史。
横向比较:真正把它们区分开的三条轴
它能不能拒绝写入?
只有那两个与代码托管平台集成的产品能,因为只有平台在那条路径上。这不是一个开源项目能补上的工具缺口——一个 pre-commit 钩子跑在开发者自己控制的机器上,所以它在结构上就只是建议性的,而那两个扫描器对「自己住在那里」是诚实的。后果是:门禁的决定是一个平台决定。如果你在 GitHub Team 或 Enterprise 上,你就买 Secret Protection;如果你在 GitLab 上,你需要 Ultimate;如果你两者都不在,那么再多的开源工具也给不了你一道门禁,而你的残余暴露面就是开发者推上去的一切。
它怎么失败,而你看不看得见这次失败?
四者都会失败放行,而方式各有四种。那两个 pre-commit 钩子在「没被装上」时失败,而没有任何东西记录这件事。GitHub 的门禁可以带着一个理由被绕过,而这会被记录。GitLab 的门禁可以被一个推送选项或一串提交信息跳过,而这会被审计;并且在它公开的尺寸阈值之上会静默跳过。两个扫描器在「这把凭据的格式没有对应检测器」时失败——Gitleaks 停在 222 条并已冻结,TruffleHog 在 700 多条并仍在增长。
按可观测性而不是按强度给它们排序,次序就把市场宣传倒了过来。一项最强、但失败不可见的控制措施,运维起来比一项较弱、但失败会发出一条你能告警的审计事件的控制措施更糟。这就是把 失败拦截与失败放行 这个问题套用到一道门禁上,而务实的规则是:每一条绕过路径都需要一个计数器,而每一个计数器都需要一个会把人呼起来的阈值。
它会不会告诉你这个发现要不要紧?
一个没有「有效性」的检测队列是无法排序的。一个老仓库里的多数发现都是死字符串——过期的密钥、已轮换的令牌、示例值——而真正要紧的那些,仅凭模式与它们无法区分。GitHub 的有效性检查与 TruffleHog 的校验都回答了这个问题;GitLab 的推送保护与 Gitleaks 都没有。既然被利用的窗口现在以分钟计,一个按「已确认有效」排序的队列就不是锦上添花:它是「分诊四把密钥」与「分诊四百个候选」之间的差别。
何时选哪个
| 情形 | 主选 | 搭配 | 为什么 |
|---|---|---|---|
| 公开仓库,任何预算 | GitHub 推送保护(免费) | 定时跑 TruffleHog | 免费门禁覆盖的正是攻击者查询的那个群体;校验把历史排出优先级 |
| GitHub Team/Enterprise,私有仓库 | Secret Protection,每提交者 19 美元 | Gitleaks pre-commit 求快 | 有效性检查与通用模式,正是私有仓库泄漏所在之处 |
| GitLab Ultimate | 密钥推送保护 | 为跳过的审计事件设告警 | 门禁很强;它公开的那些阈值就是你的残余风险 |
| 自托管平台,没有门禁 | TruffleHog 跑在 CI 里并阻断 | Gitleaks pre-commit | CI 是你能控制的、最接近门禁的东西;校验让队列保持诚实 |
| 对一个遗留单体仓库做一次性审计 | TruffleHog --results=verified | 对命中项跑 analyze | 你要的是「有效」那个子集及其触达范围,不是 4,000 个候选 |
没有谁应该只跑这四个里的一个。站得住的最小配置是「一道不是你自己写的门禁」加上「一个你定时运行的校验器」——再加上那道门禁的绕过计数器,放在一块真有人看的看板上。把这个回路造成一个由智能体驱动的工作流,是 密钥扫描与轮换智能体 的主题。
常见问题
既然开发者可以跳过,pre-commit 钩子还值得装吗?
值得,而理由与安全无关:它在「修它是免费的」那唯一一个时刻抓住了这个意外。一旦密钥进了提交,移除它就是一次历史改写;在提交之前,它只是一次编辑。请把钩子当成一项开发者体验特性,把服务端门禁当成控制措施。
GitHub 那个 19 美元包含推送保护吗?
在 Team 与 Enterprise 上,推送保护被列为随 Secret Protection 一起提供,而在公开仓库上免费。那每位活跃提交者每月 19 美元买到的是私有仓库的覆盖,加上有效性检查、通用模式,以及用于告警的 AI 检出密钥。
Gitleaks 既然冻结了,我们现在该换掉它吗?
不紧急,而且不要靠删掉它来换。它仍然能在 MIT 之下、很快地检出它所知道的那 222 种模式。请按覆盖面来规划替换:如果你的技术栈采用了令牌格式晚于冻结时点的提供方,那些就不会被抓到;而一次定时的 TruffleHog 扫描,是比一次迁移更便宜的补洞方式。
GitLab 为什么不校验密钥是否仍然有效?
它的推送保护被设计成 pre-receive 路径上的一次阻断式检查,而在那条路径上,一次到第三方提供方的网络调用会给每一次推送都加上延迟,并把一个外部依赖引入写入路径。那是一个站得住的工程取舍;它只是意味着「有效性」必须从你流水线的别处来。
攻击者能利用 GitLab 公开的那些跳过条件吗?
原则上能——一个超过 1 MiB 的 diff 不会被扫描。但现实中的威胁不是一个恶意内部人去精心构造一个 1 MiB 的 diff,而是一次普通的大重构跨过了 3,150 个路径,然后就静默地没被检查。请为跨过阈值的推送设告警;这会把一次静默跳过变成一个可复核的事件。
延伸阅读
本维基上:
- 五分钟,就是你全部的响应窗口——那份让「门禁还是扫描器」这个选择变得紧迫的微软报告。
- 面向智能体的密钥管理——一开始就把凭据放到模型触达不到的地方。
- 凭据寿命——为什么「寿命短的凭据」胜过「小心对待寿命长的凭据」。
- 失败拦截与失败放行——比较上面那四种失败模式的框架。
- 密钥扫描与轮换智能体——把这些工具周围的回路自动化。