GitLab CVE-2026-85706 未授权任意文件读取漏洞排查与修复
GitLab CE/EE 的 Repository Commits API 存在路径遍历漏洞,编号 CVE-2026-85706,CVSS 3.1 评分 10.0(AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N)。未认证的远程攻击者可读取 GitLab 服务器上任意可读文件,可能泄露 gitlab-secrets.json、database.yml、CI/CD Token、Deploy Key 等敏感凭据。
漏洞简介及影响范围
漏洞出在 /api/v4/projects/:id/repository/commits 接口:处理 file.path 参数时未做路径限制,且校验在鉴权之前执行。攻击者只需把请求路由中的一个字符做 URL 编码(例如 %63ommits)即可绕过 Workhorse 的路径匹配,由 Rails 侧正常处理。
| 分支 | 受影响版本 | 修复版本 |
|---|---|---|
| 19.3 | 19.3.0 ~ 19.3.1 | 19.3.2 |
| 19.2 | 19.2.0 ~ 19.2.5 | 19.2.6 |
| 18.7 ~ 19.1 | 18.7.0 ~ 19.1.7 | 19.1.8 |
| 19.0 | 19.0.0 ~ 19.0.8 | 19.0.9 |
| 18.11 | 18.11.0 ~ 18.11.11 | 18.11.12 |
| 18.7 ~ 18.10 | 18.7.0 ~ 18.10.x | 官方未提供修复 |
修复版本于 2026 年 9 月 10 日发布,19.0.9 与 18.11.12 于 9 月 23 日补发。该漏洞已于 2026 年 9 月 11 日被 CISA 收录进 KEV 目录,公开 PoC 与 Nuclei 模板均已出现。
利用前提是实例上至少存在一个公开项目;GitLab.com 与 GitLab Dedicated 官方已完成修复,不受影响。
一、确认版本是否在受影响区间
资产台账里的版本号经常与实际不符,以服务器上运行的版本为准。
bash
cat /opt/gitlab/embedded/service/gitlab-rails/VERSION
预期结果 :输出形如 19.3.1。落在上表受影响区间即为中招;输出 19.3.2、19.2.6、19.1.8 及以上说明已修复。
二、确认实例是否暴露公网
bash
ss -lntp | grep -E ':80|:443'
curl -s -o /dev/null -w '%{http_code}\n' https://gitlab.example.com
预期结果:第一条列出 nginx 或 gitlab-workhorse 的监听记录;第二条返回 200 或 302,说明外部可直连。仅内网可达的实例风险等级可下调,但仍需升级。
三、检索日志中的利用痕迹
正常业务不会对 commits 路由发起陌生 POST,重点看访问日志里的异常编码。
bash
grep -E "POST .*commits" /var/log/gitlab/nginx/*.log | awk '{print $(NF-1)}' | sort | uniq -c | sort -rn | head
grep -rE "%63ommits|%2[fF]" /var/log/gitlab/nginx/*.log | head
预期结果:列出向 commits 接口发起 POST 的来源 IP 及次数。若出现大量来自陌生 IP 的请求,或响应体明显大于一次提交的元数据(说明文件内容被回显),可判定已被扫描或利用。
四、备份
bash
gitlab-backup create
cp /etc/gitlab/gitlab-secrets.json /root/gitlab-secrets.json.$(date +%F)
cp /etc/gitlab/gitlab.rb /root/gitlab.rb.$(date +%F)
预期结果 :备份文件生成于 /var/opt/gitlab/backups/,secrets 与配置副本落于 /root。确认文件大小非 0 再继续。
五、升级到修复版本
以 CentOS 的 Omnibus 安装方式为例,从 19.1 分支升到 19.1.8:
bash
# Debian/Ubuntu 用 apt install gitlab-ce
yum install -y gitlab-ce-19.1.8
gitlab-ctl reconfigure
gitlab-ctl restart
预期结果 :reconfigure 结束无 error 行;restart 后各组件状态均为 run。
六、验证
bash
cat /opt/gitlab/embedded/service/gitlab-rails/VERSION
gitlab-ctl status
curl -s -o /dev/null -w '%{http_code}\n' -X POST https://gitlab.example.com/api/v4/projects/1/repository/commits
预期结果 :版本号已是修复版本,组件全部 run;最后一条返回 401 或 404(未认证被拒),不再回显任何文件内容。
七、轮换可能泄露的凭据
只要漏洞窗口期内实例对公网可达,就应视为 secrets 可能已泄露。GitLab 官方建议重置以下内容:
gitlab-secrets.json中的secret_key_base、db_key_base、otp_key_base- CI/CD Runner 注册令牌与各项目的 Runner Token
- PostgreSQL、Redis 连接密码
- 服务账号个人访问令牌(PAT)
- 部署私钥(Deploy Keys)
注意:secret_key_base 轮换后,CI/CD 变量中已加密的内容会失效,需要重新录入。
注意事项
- 18.7 ~ 18.10 分支官方未提供修复,建议直接跨分支升级到 19.1.8 及以上。
- 升级只堵住入口,不能回收已被读走的内容;确认窗口期暴露过就必须做凭据轮换。
- 临时缓解手段(下线公网访问、IP 白名单、在 WAF 拦截 commits 路由的异常编码)只能争取时间,不能替代升级。
- 判定修复是否生效,以服务端实际返回 401/404、不再回显文件内容为准。