ARTICLE · 1101740
474 个泄露的 GitHub App 私钥至今仍有效:密钥不会过期,只会被遗忘

最近安全公司 GitGuardian 发布了一份让不少开发者后背发凉的研究报告:从 2019 年至今,他们在公开渠道累计发现了 4802 个泄露的 GitHub App 私钥,逐一验证后发现,474 个私钥今天依然能正常登录,对应 440 个不同的 GitHub 应用。
很多人看到这类新闻的第一反应是:又是密钥泄露,删掉换一个不就完了?
还真不是。这批密钥暴露的不是一个"漏洞",而是一套容易被忽视的机制:GitHub App 的私钥没有有效期,不手动吊销,它就永远有效。四年前的泄露,今天的攻击者拿过来照样能进你的私有仓库。
先交代清楚背景。GitHub App 是 GitHub 官方的应用扩展机制,组织可以安装第三方应用来实现自动化——管理 Actions 令牌、做 CI 检查、同步issue等等。每个 App 在创建时会生成一对公私钥,App 用私钥签名请求,GitHub 验签后发放临时令牌,应用就能以自己的权限访问安装它的组织。
GitGuardian 的研究团队做的事情很"笨"但很有效:把多年来从公开代码、公开渠道收集到的 50 万多个暴露的 RSA 密钥筛了一遍,识别出其中 4802 个是 GitHub App 的私钥,然后逐一去 GitHub 的 API 上验证——结果 474 个至今验证通过。
这些"还活着"的密钥权限有多大?看数据:
研究报告里点名的案例很典型:一个叫 Access Tokens for GitHub Actions 的应用,私钥在 2024 年 1 月被人不小心提交到了公开仓库里。这个应用当时被大约 300 个组织安装,其中包括企业服务公司 Civica 和军工相关的 Sierra Nevada Corp。密钥泄露的位置不在这些组织的仓库里,但它们全都暴露在风险之下。类似的还有 BuildBuddy、Crusher.dev,甚至一个与美国疾控中心(CDC)相关的私有应用。
GitGuardian 表示已通知所有受影响的应用所有者。至顶网等国内技术媒体 9 月 29 日报道了这项研究。
要理解这件事为什么棘手,得先搞清楚 GitHub App 私钥的工作原理。
第一层:私钥是"通行证",不是"密码"。 App 拿私钥生成一个 JWT(一种签名令牌),发给 GitHub 换取安装访问令牌,再凭这个令牌调 API。整个过程走的是 GitHub 的官方接口——换句话说,攻击者不需要黑进任何人的电脑,不需要绕过任何防火墙,他拿着捡来的私钥和公开的 App ID,走的完全是正规通道。在组织的管理日志里,这些访问看起来和正常应用操作几乎一模一样。
第二层:私钥永不过期。 你在 GitHub 上常用的个人访问令牌(PAT)可以设置有效期,细粒度令牌也支持过期时间。但 GitHub App 的私钥不同——它就是一对普通的 RSA 密钥,生成之后不会自动作废,只有应用所有者手动"重新生成"(regenerate)才会让旧私钥失效。没人管,它就活到天荒地老。这次 474 个密钥里不少已经泄露好几年,依然畅通无阻。
第三层:权限是"批量放大器"。 普通开发者的令牌泄露,影响的是一个人的权限。但 GitHub App 的设计是"一次安装,多组织生效"——一个应用可能被几十上百个组织安装,App 的权限在每个组织里都独立生效。私钥一旦泄露,遭殃的不是应用开发者的账号,而是所有安装方的组织。这就是为什么一个 2024 年泄露的私钥,能牵连 300 个组织。
从风险分层看:功能层面,私钥失效会导致依赖该应用的自动化流程整体瘫痪,重新生成前 CI 流水线可能直接断供;安全层面,仓库读写、工作流控制、Runner 管理意味着从代码泄露到供应链投毒、内网横向移动的完整攻击链;合规层面,私有代码属于企业核心资产,这类暴露在等保、数据安全法以及客户安全审计里都属于高风险项,而且"日志里查不到异常"的特性会让泄露长期潜伏。
行业通行做法其实早就写在各类密钥管理规范里:密钥要能吊销、要定期轮换、要尽量用短时效凭证替代长期密钥。GitHub 自己也在推 Actions 的 OIDC 短期令牌方案,方向就是消灭"永远有效的钥匙"。
误区一:代码里的私钥删掉了,泄露就结束了。
这是最普遍的误会。发现私钥被提交到仓库,很多开发者的操作是删文件、提交、推送,顶多再清洗一下 git 历史。但历史改写覆盖不到已经 clone、fork 的副本,也覆盖不到各种缓存视图;更要命的是,GitHub App 私钥本身不会因为你在代码里删了它而失效——只要没人去开发者设置里点重新生成,这把"钥匙"就继续有效。GitGuardian 数出来的 474 个活密钥,就是这么留下的。正确顺序永远是:先吊销重置密钥,再考虑清洗历史。
误区二:应用是别人开发的,密钥泄露不关我事。
组织管理员常见的想法是:"我只是装了个第三方应用,它的密钥又不是我保管的。"但这正是 GitHub App 机制的传导路径:应用所有者的密钥泄露,买单的是所有安装方。300 个组织因为一个第三方应用的私钥泄露而暴露,没有一家自己的代码仓库出过错。安装一个 App,本质上是在你和组织之间给对方发了一把权限可大可小的钥匙,这把钥匙的保管水平取决于别人。
误区三:私钥泄露等于要防盗号,盯着登录日志就行。
有人会说那我盯着异常登录不就行了。问题是 App 的访问走的是官方 API 的正常签名流程,不是"登录"。没有异地 IP 暴力破解的告警,没有密码错误的日志,攻击者的每一次读取都披着"应用正常调用"的外衣。这也是这类泄露往往潜伏数年的原因——不是攻击者多高明,而是监控的姿势从一开始就没对准。
给不同角色几条能落地的检查动作。
组织管理员(今天就能做):
应用开发者(如果维护 GitHub App):
所有开发者(通用习惯):
这次研究里最扎心的细节,是那 474 个密钥里没有一个是靠高深攻击才暴露的——它们只是被提交、被遗忘、然后一直有效。安全事件里最昂贵的往往不是攻击者的技术,而是"以为删了就没事了"的误会。
密钥的世界里没有默认过期,只有主动作废。今天花十分钟盘点一下你组织里装了哪些 App、你代码里躺过哪些钥匙,可能比装十个安全产品都实在。
如果你身边也有"私钥提交过又删掉"的同事,把这篇文章转给他看看。
#GitHub #密钥安全 #供应链安全 #GitGuardian #开发者安全