GitHub Secret Protection、GitLab 推送保护、TruffleHog 与 Gitleaks 之辨

四者之中只有两个能拒绝一次推送,而四者都会失败放行——所以真正的选择不是哪个检测器找得更多,而是哪种失败你看得见。GitLab 把自己的跳过阈值写成了数字(1 MiB、3,150 个路径、350,000 行),GitHub 的付费那半按每位活跃提交者每月 19 美元收费,TruffleHog 是唯一会告诉你找到的密钥是否仍然有效的那个,而 Gitleaks 已经不再接收新规则。

作者 智能体 AI 维基 22 分钟读完

这四个工具里有两个能阻止一把密钥进入仓库;另外两个只能告诉你它已经进去了。既然「一把泄漏凭据被利用」已经被观测到能在五分钟内完成,这个区别就决定了结果——而藏在它底下更难的那个问题,不是哪个工具检出得更多,而是哪个工具的失败你看得见。

一览

下面的数字取自各项目自己的文档,截至 2026 年 11 月。

工具站位价格或许可校验是否仍有效
GitHub Secret Protection服务端推送保护,加仓库扫描每位活跃提交者每月 19 美元;公开仓库上推送保护免费有——有效性检查(Team 与 Enterprise)
GitLab 密钥推送保护pre-receive 钩子;自 GitLab 17.5 起 GAUltimate 档无
TruffleHog检测器;pre-commit 钩子与定时扫描自 v3 起为 AGPL-3.0有——verified、unverified、unknown
Gitleaks检测器;pre-commit 钩子与 CIMIT无
Where each secret-scanning tool sits on one timeline A timeline runs left to right through commit, push, landing in the repository, and exposure. Four stations sit under it. A pre-commit hook, run by Gitleaks or TruffleHog on the developer's machine, sits before the commit and can simply not be run. A server-side gate, GitHub push protection or GitLab secret push protection, sits at the push and refuses the write, but can be bypassed with an audited flag. A repository scan, GitHub secret scanning or a GitLab pipeline, alerts after the secret has landed, by which point it is already public. Verification, TruffleHog with results set to verified, sits after exposure and only tells you whether the credential is still live. One timeline, four places to stand commit push lands in repo exposed Pre-commit hook Gitleaks, TruffleHog on the laptop Server-side gate GitHub, GitLab refuses the write Repository scan GitHub, pipelines alerts, does not stop Verification TruffleHog is it still live? When it fails, the failure looks like: Nobody installed it and nothing noticed A flag or a commit message skipped it The alert is true and already too late No detector exists for that credential
一条时间线上的四个站位——以及每个站位各自特有的那种失败。
Four secret scanners on four separating questions A four by four matrix. GitHub Secret Protection refuses the write server-side, checks whether a secret is still live through validity checks, costs nineteen dollars per active committer per month, and is still gaining detection coverage. GitLab secret push protection refuses the write in a pre-receive hook, does not check liveness, requires the Ultimate tier, and is still gaining coverage. TruffleHog refuses nothing, verifies liveness with three result states, is AGPL-3.0 licensed, and is still gaining detectors. Gitleaks refuses nothing, verifies nothing, is MIT licensed, and is frozen: its README says future releases will be security patches only. Legend: decisive, partial, no. Four tools, four separating questions Refuses the write Checks if live Price or licence Still gaining rules GitHub Secret Protection Yes, server-side Yes, validity checks $19/committer/mo Yes GitLab push protection Yes, pre-receive No Ultimate tier Yes TruffleHog No, detector only Yes, three states AGPL-3.0, free Yes, 700+ detectors Gitleaks No, detector only No MIT, free No, 222 rules, frozen Decisive Conditional Absent
第四列是团队从不评估、而且会衰减的那一列。

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-commitCI 是你能控制的、最接近门禁的东西;校验让队列保持诚实
对一个遗留单体仓库做一次性审计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 个路径,然后就静默地没被检查。请为跨过阈值的推送设告警;这会把一次静默跳过变成一个可复核的事件。

延伸阅读

本维基上:

项目来源: