补丁打了却没修上:GitLab CVE-2026-97229,10.0 分未授权 RCE
10 月 4 日那篇写过一次自建 GitLab 的 10.0 分漏洞(CVE-2026-85706,未授权读任意文件)。一个月后,同一个 10.0 分又来了——这次更直接:未经身份认证就能在 GitLab 服务器上执行代码。
CVE-2026-97229,CVSS 10.0,GitLab CE/EE 均受影响。GitLab 在 10 月 12 日发布了修复版本;10 月 29 日,CISA 把它列入 Known Exploited Vulnerabilities(KEV)目录,确认在野利用,联邦机构的修复期限是 11 月 1 日——已经过了。Shadowserver 统计,11 月 1 日那个周末,全网仍有 1,000 多台未打补丁的 GitLab 服务器。

漏洞出在哪:一条正则表达式
问题出在 CI/CD 配置里的一条正则表达式。GitLab 在处理 CI/CD 配置时,会把用户提交的正则拿去编译;由于校验不足,一条精心构造的正则就能触发整数溢出(CWE-190),进而在服务器上执行任意代码。不需要登录,只需要能向 GitLab 提交 CI 配置——新注册的账号就够了。
根因不在 GitLab 自己的代码里,而在 Ruby 自带的正则引擎 Onigmo 中。这一点直接决定了这次事件的走向,也是下面 Alpine 那段教训的核心。
影响范围:19.2、19.3、19.4 三个分支
按 GitLab 官方安全发布,受影响的是:
- 19.2 系列:19.2.8 之前
- 19.3 系列:19.3.5 之前
- 19.4 系列:19.4.2 之前
修复版本对应为 19.2.8、19.3.5、19.4.2。GitLab.com 和 Dedicated 的托管客户已经由官方直接保护,不用自己动手;自建实例必须自己升级,这正是这篇文章的读者。
公开 PoC 已经出现,Metasploit 也有对应模块。EPSS 评分 65.2%,排在前 1%——这不是”理论上能打”,而是”已经有人在打”。
Alpine 的教训:升了 GitLab,漏洞还在
这件事最值得写下来的部分,是 Alpine Linux 的真实遭遇。
10 月 20 日到 21 日,一个新注册的账号向 Alpine 的 GitLab 实例提交了精心构造的 CI 配置,GitLab 的 worker 进程因此崩溃了 8 次,其中 4 次攻击者已经走到了下一步、只是最后没成。Alpine 当时升级了 GitLab,以为已经修好。10 月 26 日他们才发现:实例仍然 vulnerable。
原因很直接:这次修复不在 GitLab 自己的代码里,而在 Ruby 的补丁里。GitLab 官方打包的版本自带打过补丁的 Ruby,而 Alpine 用的镜像跑的是标准 Ruby——GitLab 升上去了,底下的 Ruby 没换,漏洞原地还在。Alpine 原话是”Our upgrade didn’t fix the vulnerability”。
10 月 27 日,Alpine 关停了实例;因为无法排除代码已被执行的可能,他们没有只做清理,而是整台服务器从头重建,并重置了 GitLab 的密钥。10 月 29 日,实例以 GitLab 19.3.7 + Ruby 3.3.13 重新上线。Ruby 官方的修复版本是 3.3.13、3.4.12、4.0.9(含同一批 Onigmo 溢出的全部四个 CVE)。
这个教训可以浓缩成一句话:对自建 GitLab 来说,”GitLab 版本号对了”不等于”修好了”,还要核对底下的 Ruby 版本。用官方 Omnibus 包的用户相对省心——补丁 Ruby 随包走;自己用系统 Ruby、容器镜像或源码部署的,升级后必须单独确认 Ruby 已到修复版本,否则就是 Alpine 的翻版:补丁打了,洞还在。
DBA 为什么要在乎一个 GitLab 漏洞
自建 GitLab 的后端就是 PostgreSQL,CI 变量、Runner 凭据、仓库里的各类密钥都围着这台服务器转。一次未授权 RCE,约等于整台服务器的凭据体系按”已泄露”处理。Alpine 的处理方式就是标准答案:重建服务器、重置密码、重置双因素认证、重置各类 token 和已存密钥、更换 GitLab 自身的 secret key——不是”打个补丁就完事”,而是按入侵事件走完一整套。
该干什么,照着做
- 立即升级到 19.2.8、19.3.5 或 19.4.2(按自己所在的分支),能升更新的就升更新的
- 升级后核对 Ruby 版本:确认 Ruby 已到 3.3.13 / 3.4.12 / 4.0.9 之一;用官方 Omnibus 包的核对包版本,自行部署的单独核对 Ruby
- 排查 10 月 20 日前后的日志:重点看新注册账号提交的 CI 配置、worker 进程的异常崩溃、以及任何非预期的出站连接
- 看有没有异常:多出来的用户、改动过的 CI 变量、Runner 配置里没见过的改动、仓库里多出来的文件
- 有入侵迹象就按事件处理:从可信来源重建;轮换数据库凭据、GitLab 的 secret key、CI 变量里的全部密钥、以及 Runner 和集成方的 token
联邦机构的期限 11 月 1 日已经过了,全网还有 1,000 多台没打补丁。10 月 4 日那篇是”读文件”,这次是”执行代码”——同一个 10.0 分,危害上了一个台阶。
原文作者: liups.com
原文链接: https://liups.com/posts/aac66d4f/
许可协议: 知识共享署名-非商业性使用 4.0 国际许可协议