GitHub 的上下文感知密钥分类器提升检测质量,加权接受度提高 11.5%,扫描执行时间中位数减少 86%。文章介绍其如何发现更多密钥并减少检测噪声。
按所有者加权的告警准确率
更低的扫描执行时间中位数
紧凑模型与远程 LLM 调用的对比
当开发者信任扫描结果时,Secret scanning 才能发挥最佳效果。检出得太少,真实凭据就可能留在仓库里;告警太多,开发者又可能把时间花在排查那些并非秘密的字符串上。
通用秘密让这种平衡尤其难以把握。同一个字符串,可能是真实凭据,也可能只是文档中的占位符,因此,检测时必须理解周围的代码和文本。
为了解决这个问题,我们针对 GitHub 的产品需求,专门训练了一个秘密分类器:既要区分真实凭据和看起来像凭据的字符串,也要满足大规模扫描对速度和效率的要求。
在配套文章《秘密保护必须跟上软件发展的规模》中,我们解释了为什么秘密保护必须跟上 AI 加速的软件开发。在这里,我们将深入介绍支撑这项工作的上下文感知分类器:我们如何设计、训练和评估它,从而发现更多真实秘密,同时减少无效告警。
GitHub secret scanning 在两个关键时点发挥作用:
我们开发了一个快速分类器。与此前基于 LLM 的流水线相比,它将 post-push 扫描执行时间的中位数降低了 86%。这样的效率,让我们能够把通用秘密检测扩展到 push protection,在开发者 push 变更之前返回结果,而不再只是在代码提交后进行检测。
模型在文件第 5 行检测到秘密后,Secret scanning 通过 push protection 阻止了这次提交。
结构化凭据通常带有独特的前缀、长度、字符集或校验和。通用秘密则未必如此。它们在语法上可能与构建标识符、校验和、资源哈希、示例值及其他非敏感字符串重叠。上下文才是决定性的信号。
| 很可能是真实凭据 | 很可能是无害的相似字符串 |
|---|---|
| 在生产数据库 URL 旁赋值的密码 | 测试夹具中同样形似密码的值 |
| 部署配置中的连接字符串 | 设置指南中指向 localhost 的连接字符串 |
| 绑定到 API 凭据的高熵值 | 高熵的校验和、构建 ID 或资源哈希 |
这些情况属于难负例(hard negatives):字符串符合凭据模式,却不是可用的凭据。增加规则可以过滤掉其中一部分,但每增加一个例外,都可能漏掉真实秘密。学习型分类器则可以利用文件路径、秘密类型、变量名,以及附近的代码或文本等信号。
因此,我们推出了采用两阶段流水线的新扫描器:
用户接受率提高了 11.5%,减少了误报。
Post-push 秘密检测执行时间缩短了 86%。
与基于 LLM 的流水线相比,成本节省超过 98%。
扫描内容时,regex 模式会广泛匹配并标记所有看起来像凭据的字符串,避免在最初阶段漏掉真实秘密。随后,每个候选项都会交给经过 fine-tuning 的 ModernBERT 分类器。分类器会结合文件路径、变量名和周围的代码读取候选值,估计它是真实秘密的可能性。高置信度的检测结果会生成告警,而占位符、测试夹具和校验和等相似字符串,则会在到达开发者之前被过滤掉。
这里一个重要的设计选择是:模型并不取代确定性扫描,而是对其进行补充。Regex 仍然是快速查找候选字符串的合适工具。分类器则用于机器学习最能发挥作用的环节:区分“看起来像秘密”和“很可能是真实秘密”。
分类器模型会尽力区分“看起来像秘密”和“很可能是真实秘密”。
大多数误报并不是随机出现的。它们属于难负例:字符串符合凭据模式,却不是可用凭据。例如,文档占位符、测试中的简单示例、经过遮蔽的值、非敏感 ID,以及生成的测试夹具。这些内容很容易被 regex 匹配到,而纯规则系统很难在过滤它们的同时,避免误删真实秘密。
ModernBERT 的优势在于,它能够结合附近的代码和文本读取候选项,提供可与 LLM 媲美的上下文理解能力,同时不必承担生成自然语言输出带来的延迟和计算开销。例如,一个候选项周围如果出现了“example”“dummy”“fake”或“replace-me”等词,它的风险可能低于部署文件中赋给环境变量的候选项。分类器通过带标签的示例学习这些上下文差异,无须工程师把每个例外都编码成另一条规则。
我们选择 ModernBERT,是因为它非常适合这项工作:体积小、效率高,而且擅长对代码周边文本进行分类。对于 secret scanning,模型需要在较短的候选上下文窗口内,以高吞吐量和低延迟做出经过校准的判断。
因此,在流水线的这一阶段,经过 fine-tuning 的 encoder 分类器比通用 LLM 更适合部署为推理服务。模型可以直接围绕我们的决策边界进行训练,并使用真正影响 secret scanning 质量的召回率和准确率指标来评估。
挑战在于:对于那些仅凭语法就会被误导的情况,如何找到有代表性的数据。我们的训练和评估策略结合了三类来源:
合成数据行在纳入数据集之前,会经过确定性验证和基于模型的质量审查。训练重点放在真实秘密、贴近实际的误报,以及经常让纯 regex 方法混淆的难负例上。每个模型输入都包含候选值、文件路径、秘密类型,以及限定范围内的周围上下文。我们通过离线评估选择阈值,再在接近生产环境的流量上验证模型行为,之后才扩大部署范围。
在划分数据集之前,我们会把来自同一仓库、具有相同候选值,或属于同一示例的数据行归为一组,确保近似重复的样本不会同时出现在训练集和评估集中。
训练聚焦于对告警质量最重要的情况:真实秘密、贴近实际的误报,以及 regex 经常匹配到的难负例。输入表示包含候选秘密字符串、文件路径、类型,以及限定范围内的周围上下文。输出是一个分类分数,扫描器据此决定候选项是否进入后续流程。
我们的优化围绕产品需要做出的权衡展开:在保持或提高召回率的同时,减少误报和服务成本。实际操作中,我们先通过离线评估选择分类器阈值,再在接近生产环境的流量上验证,之后才部署上线。
最重要的训练原则,是让模型看到那些容易混淆的示例。我们纳入了语法上与真实秘密相似、语义上却不同的候选项,让模型不仅学会秘密长什么样,也学会误报在上下文中是什么样。
训练完成的模型会导出为 ONNX 格式,并采用 8-bit 量化,以实现快速推理。
| 线上结果 | 相比此前 LLM 流水线的变化 | 衡量内容 |
|---|---|---|
| 按仓库所有者加权的接受率 | 提高 11.5% | 客户对检测结果的接受程度 |
| Post-push 扫描执行时间中位数 | 降低 86% | 生产环境中的扫描执行时间 |
| 服务成本 | 降低超过 98% | 紧凑分类器相对于远程 LLM 调用的成本 |
经过 fine-tuning 的模型与此前 LLM 流水线的客户 A/B 评估结果。
我们分两个阶段评估了新流水线在生产环境中的效果:先在相同的公开流量上与生产基线比较,再通过客户 A/B 实验验证。
最好的安全工具,是开发者愿意信任并使用的工具。更高的准确率意味着更少的干扰性告警;更高的召回率意味着能够发现更多真实秘密;更低的成本意味着我们可以持续扩大覆盖范围,而不会让扫描变得昂贵到难以承受。
对于开发者和安全团队,这应该意味着更少的误报,以及在最容易引入秘密的地方获得更快的反馈:commit、pull request 和日常开发流程。
混合系统很强大。Regex 为我们提供速度、透明度和广泛的候选覆盖;ModernBERT 则提供通过学习获得的上下文理解能力,并减少误报。在这个产品的约束条件下,两者结合的效果优于单独使用任何一种方法。
我们也认识到,模型大小并不等同于模型的实用价值。当任务范围明确、决策边界可衡量,而且服务效率至关重要时,一个更小、经过 fine-tuning 的分类器可能就是合适的答案。
这是让 secret scanning 更准确、更易扩展、更易使用的一步。接下来,我们将重点关注两个方向:
衷心感谢 GitHub 和 Microsoft 的工程、科研及产品团队,感谢他们为这款新的秘密扫描器构建训练数据、评估套件、推理服务栈和部署计划。
作为 Microsoft CoreAI 的 Senior Research Scientist,我为 GitHub Copilot 开发 Agent 模型编排和路由技术。我的研究重点包括自适应模型选择、多模型协作、长时间跨度的 Agent 工作流,以及开发者安全。
作为 Microsoft CoreAI 的 Partner Applied Science Manager,我领导一个应用研究团队,通过 ML 和 AI 为开发者生产力带来可衡量的提升。我们持续改进模型,并应用 in-context learning,为开发者提供更深入、能理解上下文的帮助,推动 GitHub Copilot 在 Completion、Chat、Code Review 和 Agent 工作流方面持续演进。
了解如何向仓库添加 custom instructions 和 skills、使用 custom agents,以及连接 Playwright 等 MCP server。
在网络安全意识月启动之际,GitHub Bug Bounty 团队聚焦研究员 @vaib25vicky,探讨其在 GitHub 上进行安全研究的方法、技巧和经历。
开发者并没有变得更粗心,而是发展速度已经超过了他们能应对的范围。让开发者能够创造更多软件的工具,也应该承担更多保护软件的工作。