Security | CVE-2026-85706 GitLab 未授权任意文件读取漏洞分析


免责声明

本文由 LLM 参与创作

本文内容仅供学习与研究使用,基于 GitLab 官方已公开的补丁与安全公告整理,
目的在于帮助自建 GitLab 实例的运维与安全研究人员理解漏洞成因、评估自身风险。
文中不提供可直接利用的攻击工具,所有验证均在本地隔离环境中完成。
请勿将本文内容用于任何未授权的测试或非法用途,由此产生的一切后果由使用者自行承担。

图 1 · 漏洞概览卡:CVE-2026-85706 基本信息与披露节奏

0x00 引言

九月初的 GitLab 安全更新里,有一个 CVSS 10.0 的洞格外扎眼:仓库 commits API 存在路径穿越,未授权用户可读取服务器任意文件

这已经是 GitLab「未授权读文件」家族的不知道第几位成员了。比较有意思的是这次的两个根因叠得很典型——一个端点漏了鉴权,同时它又直接信任了客户端可控的文件路径,两件事凑一起刚好构成一条完整的攻击链。

更值得关注的是时间线:09-10 发补丁,09-11 WatchTowr 就观测到在野探测,之后进了 CISA 的 KEV 目录。补丁本身就是最好的漏洞说明书,这次也不例外,diff 一出来技术细节基本就藏不住了。

这篇博客就来完整过一遍这个洞:补丁怎么定位、根因在哪、官方怎么修的,以及自建实例该怎么排查。

0x01 漏洞概览

CVE CVE-2026-85706
产品 GitLab CE / EE(自建实例
类型 路径穿越 + 鉴权缺失 → 未授权任意文件读取
CWE CWE-22 路径穿越
CVSS 10.0 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N
影响版本 18.7 ≤ v < 19.1.8;19.2 ≤ v < 19.2.6;19.3 ≤ v < 19.3.2
修复版本 19.1.8 / 19.2.6 / 19.3.2
时间线 09-10 发布补丁 → 09-11 观测到在野探测 → 随后收录 CISA KEV
报告者 s3ntago(HackerOne)

两点补充说明:

  • GitLab.com 与 GitLab Dedicated 不受影响,官方在公开披露前就已修复,风险仅限自建实例。
  • 漏洞本身影响面是机密性(读文件),不直接导致完整性/可用性破坏。但读到的可能是 secrets.yml,那就是升级到 RCE 的前置条件了。

官方公告:https://docs.gitlab.com/releases/patches/patch-release-gitlab-19-3-2-released/

0x02 定位修复补丁

GitLab 的补丁发布流程比较规范,安全修复会单独走 security-* 前缀的分支,这给定位省了不少事。

# commit: 0ff7b6b291
#   "Fix unauthenticated arbitrary local file read in commits API"
# branch: security-627748-workhorsefile-lfi-19-3

v19.3.1-eev19.3.2-ee 做 compare,68 个 commit、129 个 diff 看着挺唬人,但真正跟这个洞相关的只有 3 个源文件,其余都是常规的版本整理。

文件 改动 作用
lib/api/commits.rb +1 POST :id/repository/commits 补上 authenticate!
lib/api/files.rb +2 POST/PUT :id/repository/files/:file_path 补上 authenticate!
lib/api/helpers/commits_body_uploader_helper.rb +21/-11 路径来源从 params['file.path'] 改为 UploadedFile(核心)

后一个文件是重头戏,前两个是顺手补上的鉴权缺口——注意 files.rb 也被改了,说明同一类问题在文件 API 上也存在。

0x03 根因分析

这个洞是两个根因叠加出来的,单独看任何一个都不至于这么严重,凑在一起才成了完整的利用链。

0x03.1 背景:Workhorse 为什么被设计成这样

要理解这两个根因,得先知道 GitLab 为什么会有 file.path 这套东西。

Workhorse 是 GitLab 的「智能反向代理」,用 Go 写的一层,跑在 Rails/Puma 前面,拦截所有进出 GitLab 的 HTTP 请求。它存在的理由很朴素:Ruby 处理大流量 I/O 太吃力。文件上传下载、git 的 push/pull、归档下载这类「长请求」如果直接在 Rails 里处理,会长时间占住一个 Ruby 进程和大块内存——官方文档的说法是,Workhorse 和 Puma 的内存占用能差一个数量级。

所以分工是:

  • Workhorse 负责 I/O:把大文件请求体缓冲到磁盘的临时文件,或直接对接对象存储、Gitaly;
  • Rails 负责业务与鉴权:该不该放行、这个文件属于谁,由 Rails 说了算。

对文件上传,标准流程是:Workhorse 先把上传体写到磁盘,再把「临时文件路径」经可信的请求头交给 Rails,Rails 拿到路径后按需读取。file.pathfile.size 这些参数,本来的设计意图是由 Workhorse 落盘后回填给 Rails 用——最终形态应该是一个 Rack 解析出来的 UploadedFile 对象,它的 .path 指向那个临时文件。

这个设计本身没问题。真正的毛病出在下面两点:路径来源被写错了(信了客户端 body 里可伪造的 file.path,而不是 UploadedFile.path),以及压根没做用户鉴权。

0x03.2 根因一:鉴权缺失

# lib/api/commits.rb 修复前
post ':id/repository/commits' do
  require_gitlab_workhorse!
  # ❌ 缺 authenticate! —— 压根没做用户鉴权
  attrs = file_params_from_body_upload

这里最容易踩的坑是 require_gitlab_workhorse! 到底管什么。它只校验「请求是经由 Workhorse 反向代理转发进来的」(验 Workhorse 的签名),而 Workhorse 对未登录的请求同样会加签名

换句话说:

Workhorse 签名 ≠ 用户鉴权

另外那一行 route_setting :authorization, permissions: :create_commit 也很有迷惑性——它只是声明这个端点需要什么权限,供文档和中间件参考,真正的拦截靠的是显式的 authenticate!,而这里恰好漏了。

0x03.3 根因二:信任客户端可控的 file.path

# commits_body_uploader_helper.rb 修复前
def file_params_from_body_upload
  file_path = params['file.path']              # ❌ 直接信客户端参数
  bad_request!('local file not present') unless File.exist?(file_path)

  check_large_request_rate_limit!(params['file.size'])

  media_type = Rack::MediaType.type(params['Content-Type'])
  if media_type == 'multipart/form-data'
    env = { 'rack.input' => File.open(file_path) }        # ❌ 打开任意路径
  elsif media_type == 'application/x-www-form-urlencoded'
    Rack::Utils.parse_nested_query(File.read(file_path))  # ❌ 读任意路径
  elsif media_type == 'application/json'
    Oj.load_file(file_path)                              # ❌ 读任意路径
  end
end

file.path 完全由请求方控制,既没有路径白名单,也没有 File.basename 或穿越字符清理,拿到就直接往 File.open / File.read / Oj.load_file 里塞。

而且那行 File.exist? 检查还额外送了个侧信道——报错信息 local file not present 直接暴露了目标文件在不在。

0x04 攻击链

把两个根因串起来,完整链路是这样的:

图 2 · 攻击链:两个根因叠加才构成完整的未授权读取链

POST /api/v4/projects/:id/repository/commits HTTP/1.1
Host: gitlab.example.com
Content-Type: multipart/form-data; boundary=----x

------x
Content-Disposition: form-data; name="file.path"

/var/opt/gitlab/gitlab-rails/etc/secrets.yml
------x--
  1. 构造一个不带任何 tokenPOST /api/v4/projects/:id/repository/commits
  2. body 里带上 file.path=<任意本地路径>file.size=<任意值>,并按需指定 Content-Type
  3. 请求经 Workhorse 转发并加上签名 → require_gitlab_workhorse! 顺利通过(它不验用户身份)
  4. 旧代码直接把 file.path 当成服务器本地路径采纳
  5. File.read(file_path) 把目标文件读进流程,交给 parse_nested_query 解析——文件内容不会直接回显,只有解析失败时,报错信息才会带出部分内容
  6. 三个分支(multipart / urlencoded / json)都能读文件,只要挑一个 Content-Type 走通就行

0x04.1 可读目标与读取特性

以 GitLab 服务账号的权限为界,file.path 理论上可以指向任意文件,但得先拎清这个洞的读取通道到底长什么样——它并不是「读文件 → 把内容原样回显给你」:

  • 文件被读进内存后,是当成请求体来解析(urlencoded / multipart / JSON 三选一),解析结果本该是创建 commit 的参数;
  • 只有解析或后续校验失败时,错误信息才会把「部分内容」带出来——具体是被解析器当作参数名、又恰好触发错误的那些片段;
  • 所以能读到多少,取决于目标文件的内容格式:
    • 内容里有非法 % 编码 → 回显出错位置附近几个字节;
    • 内容里含 [ / ] 触发参数类型冲突 → 回显一整段参数名;
    • 不含 & / = / % / [ 的普通文件(比如 /etc/passwd)→ urlencoded 解析会「成功」,整段内容被塞成一个参数名静默进入流程,后续报错并不包含它,反而读不到东西

换句话说:它是借错误信息间接泄露片段,不是整文件下载,也未必「任意文件都能读出来」。这也是公开 PoC 用「探测不存在的文件」来判定漏洞、而不是直接读文件的原因——要稳定读到内容,得挑格式对得上的目标文件。

高价值目标仍是密钥文件(secrets.yml / gitlab-secrets.json),但得现实一点:GitLab 的加密主密钥是完整随机密钥,AES 解密需要完整值,靠「片段」是解不密的。真正的危害在于——一旦借某个错误路径拿到了完整密钥(或足够长的连续内容),就能解密 CI/CD 变量、接管 Runner。能不能拿到完整值,需要针对具体目标实测。

官方修复时用了个 SECRET-CANARY-627748 文件做验证:修复前 canary 内容会被读出,修复后请求返回 401 且 canary 不泄露

0x05 官方修复方案

官方的修复思路很清晰,两条线同时下手。

# 修复后:三处端点补上鉴权
post ':id/repository/commits' do
  require_gitlab_workhorse!
  authenticate!          # ✅ 新增
  ...

# 修复后:只信 middleware 定稿的 UploadedFile
def file_params_from_body_upload
  uploaded_file = params[:file]
  bad_request!('file is invalid') unless uploaded_file.is_a?(::UploadedFile)  # ✅ 类型校验
  file_path = uploaded_file.path    # ✅ 指向 Rack 解析 multipart 后的真实 tempfile
  bad_request!('local file not present') unless file_path.present? && File.exist?(file_path)
  check_large_request_rate_limit!(uploaded_file.size)   # ✅ size 也从 UploadedFile 取
  1. 鉴权前置 —— 新增的 workhorse_authorize_commits_body_upload! 注释里写得明明白白:*”Authenticate before Workhorse buffers the request body to disk”*。在 Workhorse 把请求体落盘之前就把鉴权做掉,既堵住未授权访问,也避免无谓的磁盘写入。
  2. 路径只信 middleware —— UploadedFile.path 是 Rack 解析 multipart 之后生成的缓冲 tempfile,是个服务端可控的路径,不再是客户端能随便指的字符串。同时 size 也改从 UploadedFile 取,避免并发修改带来的 TOCTOU 隐患。

0x06 检测与响应

0x06.1 日志排查

重点看 commits API 上带了 file.path 的 POST 请求,尤其是没带 token 的那些

# 从 GitLab 日志里捞可疑请求
POST /api/v4/projects/{id}/repository/commits/   (body 含 file.path)

自建实例的 production.log / Workhorse 访问日志里都能找到痕迹。

0x06.2 处置建议

  • 升级到 19.3.2 / 19.2.6 / 19.1.8。注意这次带 DB 迁移,单节点升级会有停机窗口,记得排期。
  • 如果怀疑已经被打过,按凭据泄露处置:轮换 CI/CD 变量、各类 token、部署密钥,以及 secrets.yml 里的加密主密钥和相关凭据。

0x07 GitLab 读文件漏洞家族

前面提到这是「家族」里不知道第几位成员。真把这个家族的成员摊开来看,会发现这支血脉比印象里长得多 —— 从 2013 年一直延续到现在,有 CVE 编号的就有三十多个。

为了不凭印象说话,我把 NVD 上 GitLab 的记录全量拉了下来(按 cpe:2.3:a:gitlab:gitlab 匹配,当时是 1400 余条),再按「路径穿越 / 任意文件读」的语义筛了一遍,得到下面这份年表。

0x07.1 完整年表

图 3 · 年份分布:2020 年单年 11 个,是全家族峰值

CVE 年份 触发点 后果 CVSS
CVE-2013-4582 2013 gitlab-shell(create_tag / import_project 等) 本地文件信息写入仓库元数据 6.5
CVE-2016-9086 2016 import/export project(tar 内符号链接) 读服务账号可访问的任意文件 6.5
CVE-2017-0918 2017 CI runner 路径穿越 → RCE 8.8
CVE-2018-14364 2018 projects import 目录穿越 + 写 → RCE 9.8
CVE-2018-19572 2018 GitLab Pages chroot 符号链接 TOCTOU 越权读文件 5.9
CVE-2018-19856 2018 Templates API 目录穿越 7.5
CVE-2018-20229 2018 未细公开 目录穿越 7.5
CVE-2019-6240 2019 未细公开 目录穿越 7.5
CVE-2019-6783 2019 GitLab Pages 目录穿越 → RCE 8.8
CVE-2019-19088 2019 未细公开(EE 11.3~12.4.2) 目录穿越 9.8
CVE-2020-6833 2020 Workhorse(请求走私) 包与文件泄露 7.5
CVE-2020-7966 2020 未细公开(EE 11.11~12.7.2) 目录穿越 7.5
CVE-2020-10086 2020 某端点未细公开 任意文件读 5.3
CVE-2020-10953 2020 NPM 功能 路径穿越 7.5
CVE-2020-10977 2020 move issue 读 secrets.yml → 升级 RCE 5.5
CVE-2020-11505 2020 Workhorse(请求走私) NuGet 包与文件泄露 7.5
CVE-2020-11506 2020 Workhorse(请求走私) 构件上传与文件泄露 7.5
CVE-2020-13298 2020 Conan 包上传 参数校验不足 → 有限文件泄露 7.2
CVE-2020-13355 2020 LFS 上传 路径穿越覆盖指定文件 7.5
CVE-2020-13356 2020 绕过 Multipart 保护 读指定路径文件 8.2
CVE-2020-26405 2020 包上传 路径穿越写任意位置 7.1
CVE-2021-22190 2021 Workhorse 路径穿越泄露 JWT 8.5
CVE-2021-22201 2021 特制导入文件 读服务器文件 9.6
CVE-2021-22203 2021 Wiki 页面 任意文件读 7.5
CVE-2021-22234 2021 design image 任意文件读 9.6
CVE-2022-0244 2022 group 导入 任意文件读 8.6
CVE-2022-2531 2022 Grafana API 认证缺失 + 路径穿越 5.3
CVE-2022-3067 2022 Import 功能 读任意项目内容 6.5
CVE-2023-2825 2023 uploads 静态文件服务 未授权读任意文件 10.0
CVE-2024-2434 2024 未细公开(16.9~16.11) 路径穿越 → DoS + 受限文件读 8.5
CVE-2025-1754 2025 公开项目 API 未授权上传任意文件 5.3
CVE-2026-9204 2026 仓库导入(次 URL 校验不足) 认证用户读 Gitaly 任意文件 5.3
CVE-2026-10053 2026 包注册表 路径穿越 → RCE 8.5
CVE-2026-85706 2026 repository commits API 未授权读任意文件 10.0

0x07.2 按触发点归类

图 4 · 家族时间线:34 个成员按年份铺开,颜色代表 CVSS 严重度

把上面这些按「出问题的位置」归类,聚集得很明显:

上传、静态文件与包管理(9 个)

CVE-2018-19572CVE-2019-6783CVE-2023-2825CVE-2020-10953CVE-2020-13298CVE-2020-13355CVE-2020-26405CVE-2025-1754CVE-2026-10053

这是数量最多的一类。uploads 静态文件服务、GitLab Pages、LFS、NPM、Conan、包注册表——共同点都是「文件名/路径由客户端提供,服务端直接拼接到存储路径上」。2023 年的 2825 和 2026 年的 10053 分别踩在 uploads 和包注册表上,说明这条路一直没被走完。

导入 / 导出 / 移动(7 个)

CVE-2016-9086CVE-2018-14364CVE-2020-10977CVE-2021-22201CVE-2022-0244CVE-2022-3067CVE-2026-9204

归档解析是重灾区。CVE-2016-9086 是 tar 包里的符号链接没校验,CVE-2021-22201 是「特制导入文件」直接读到服务器文件(CVSS 9.6),CVE-2026-9204 则是仓库导入时的次 URL 校验不足。只要有个功能需要解开用户提供的压缩包或从外部拉取,路径就要重新审一遍。

Workhorse 与请求处理(5 个)

CVE-2020-6833CVE-2020-11505CVE-2020-11506CVE-2020-13356CVE-2021-22190

这一组都跟 Workhorse 这层反向代理有关:三个是请求走私导致的文件泄露,CVE-2021-22190 是 Workhorse 里的路径穿越直接泄了 JWT。这也解释了本文漏洞为什么能绕过鉴权——只要把请求交给 Workhorse 处理,鉴权就得在应用层自己补上。

渲染器与解析器(3 个)

CVE-2017-0918(CI runner)、CVE-2021-22203(Wiki 页面)、CVE-2021-22234(design image)

API 的文件路径参数(2 个)

CVE-2018-19856(Templates API)、CVE-2026-85706(commits API,本文主角)

数量少,但含金量高——两个都能未授权直接读文件。

gitlab-shell 与仓库操作(1 个)

CVE-2013-4582——家族里最老的一位,create_tag / import_project 等函数会把本地文件内容带进仓库元数据。

端点未细公开(7 个)

CVE-2018-20229CVE-2019-6240CVE-2019-19088CVE-2020-7966CVE-2020-10086CVE-2022-2531CVE-2024-2434

官方公告只写了「allows Directory Traversal」这类一句话描述,没公开具体端点。按 90 天披露惯例,这些细节当年也是压着的。

0x07.3 十三年的规律

时间上有一个极其突出的峰值。

把 34 个成员按年份排一下:

2013  2016  2017  2018  2019  2020  2021  2022  2023  2024  2025  2026
 1     1     1     4     3     11    4     3     1     1     1     3

2020 年一年就占了 11 个,比前后任何一年都多出一大截。2018 ~ 2021 构成第一波高发期(4 / 3 / 11 / 4),之后 2022 ~ 2025 明显缓了下来(3 / 1 / 1 / 1),到 2026 年又回到 3 个。

这里有个反直觉的点:2023 年只出了 1 个,就是那个 CVSS 10.0 的 2825。数量少不代表动静小,单条漏洞的影响完全可以盖过一整年的小漏洞。

触发点在迁移。

2013  gitlab-shell
2018  uploads 静态文件服务、GitLab Pages
2020  Workhorse 绕过、包管理(NPM / Conan / LFS)
2021  渲染器(Wiki)、导入文件
2022  导入功能、Grafana API
2023  uploads(2825)
2026  包注册表、commits API

这条线基本跟着 GitLab 的功能走:哪块新功能铺开,哪块就先出事。包管理这块尤其典型——2020 年就在 NPM、Conan 和包上传上连栽三个(CVE-2020-10953CVE-2020-13298CVE-2020-26405),2026 年的 CVE-2026-10053 又在包注册表上重演了一遍。

而本文的 commits API 属于「API 层」这一波。整份年表里 API 直接出问题的只有两条——2018 年的 Templates API(CVE-2018-19856)和本文的 CVE-2026-85706——但两条都是未授权就能读文件。这条路走得少,含金量却最高。

图 5 · CVSS 严重度构成:9 分以上 6 个,两个满分

满分的公式很固定。

两个 10.0(2825、85706)的共同点完全一致:未授权(PR:N)+ 能读到 secrets.yml 这类凭据文件。CVSS 向量也几乎同一串:

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N

只要凑齐「不用登录」加「能摸到主密钥」,评分就直接顶格——因为读 secrets.yml 等于拿下所有加密数据,实际危害远超单纯的读文件。

失误就三种,反复出现。

  1. 路径拼接不做清理——不调用 File.basename、没有路径白名单,.. 直接生效。这是绝大多数成员的病根。
  2. 鉴权只声明不执行——route_setting :authorization 之类的声明写了,但真正的 authenticate! 漏了,或者被 require_gitlab_workhorse! 这类「看起来像鉴权」的校验顶替了。
  3. 信任客户端可控的值——路径、size、Content-Type 直接拿来用,不做服务端二次确认。

0x07.4 本文漏洞在这个家族里的位置

CVE-2026-85706 之所以值得单独写一篇,是因为它把上面第 2 条和第 3 条同时踩中了

  • commits API 漏了 authenticate!(第 2 条:鉴权缺失)
  • 又直接信任客户端传进来的 file.path(第 3 条:信任可控值)

单看每一条,在家族史里都算「常规操作」;但两条叠在同一个端点上,就凑出了第 4 个满分成员。

0x08 PoC 现状与复现思路

截至本文整理时,公开 PoC 已经出现了(Rubby2001/CVE-POCS 下的 CVE-2026-85706),但它是「非破坏性存在检测」,不是完整利用

这个 PoC 的思路很克制,也很值得防御方一看:

  • 探测路径故意指向一个不存在的文件(如 /tmp/.cve-2026-85706-nonexistent-probe),只凭响应差异判定漏洞是否存在,不读取、不显示、不外传任何真实文件内容
  • 判据就一句话:
    • 400 且 body 出现 local file not presentVULNERABLE(服务端信了客户端 file.path
    • 401PATCHEDauthenticate! 已生效)
    • 403 + workhorse 字样 → NOT REACHABLE(请求没走 Workhorse 代理路径,检查反向代理配置)
    • 404 → 项目 ID 不对,换个真实存在的 --project-id
  • 请求里带了 Gitlab-Workhorse: yes 头,确保走标准的 Workhorse → Rails 路径。

纯从学习角度复现,比之前更简单了:

# 1. 起一个 19.3.1 的 docker 实例
# 2. 用公开 PoC 跑一遍存在性检测,核对判定矩阵各分支
# 3. 想观察实际读取效果,把探测路径换成实验环境里的已知文件(仅限自有授权环境)

参考 CVE-2023-2825 的 ..%2F 多层编码绕过思路,大概率能迁移——根因是同一类。

0x09 小结

这个洞技术上不算复杂,但两个根因叠得很典型:

  • require_gitlab_workhorse! 不等于鉴权。它只证明请求经过了 Workhorse,而 Workhorse 对着未登录请求照样签名。这个认知误区值得记一下。
  • 客户端可控的路径绝不能直接落进文件系统调用,哪怕做了 File.exist? 检查也不行——那个检查本身还会变成侧信道。
  • 「读文件」不等于「文件内容会回显给你」。这类洞的读取通道常常是借错误信息间接带出片段,能不能读到、能读多少,取决于目标文件格式;也别轻信「密钥碎片即可解密」的说法——完整密钥才解得动。

从防御角度看,最有价值的信息其实是时间线:补丁发布 → 次日在野探测 → 进 KEV。这个节奏下,自建 GitLab 实例的升级窗口基本只有一两天。这次带了 DB 迁移还没法热更,压力就更大了。

对自建实例的运维人员来说,结论很朴素:能升就赶紧升,怀疑被打过就按凭据泄露处理,该轮换的都轮换掉。

0x0A 写在最后:关于这份免责声明

再强调一遍开头那段免责声明——本文主要由 LLM 参与创作,从资料检索、GitLab 与 Rack 源码比对、公开 PoC 分析到初稿撰写,大模型都深度参与其中。

本文仅供学习与研究:内容基于 GitLab 已公开的补丁与安全公告整理,不含可直接利用的攻击工具,所有验证都在本地隔离环境完成。请勿将文中内容用于任何未授权的测试或非法用途。

坦白讲,这算是一次「AI 大模型时代下怎么做安全研究」的小小探索,这篇文章的写作几乎都由 LLM 完成:补丁 diff 能快速读完;十三年、三十多个成员的家族史能一次拉全;像「读取通道到底能带出多少内容」这种藏在解析器里的细节,也能顺着源码一路啃下去。

AI 能把这件事加速很多,但技术结论的最终确认,还是得回到源码和实测上。如果你也在用类似方式写技术文章,欢迎交流。

0xFF 参考链接


文章作者: MiaoTony
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 MiaoTony !
评论
 本篇
Security | CVE-2026-85706 GitLab 未授权任意文件读取漏洞分析 Security | CVE-2026-85706 GitLab 未授权任意文件读取漏洞分析
九月初 GitLab 放了个 CVSS 10.0 的紧急补丁,仓库 commits API 既漏了鉴权、又直接信了客户端可控的文件路径,未登录就能读服务器上的任意文件。补丁发布第二天就有在野探测,随后进了 CISA KEV 目录。这篇博客就从 patch diff 入手,扒一扒这个洞的两个根因和官方的修复思路。
2026-09-12
下一篇 
CTF | 2023 强网杯 S7 线上赛 WriteUp CTF | 2023 强网杯 S7 线上赛 WriteUp
大概是喵喵的最后一届强网杯,今年继续和校队的师傅们一起打了下,感觉这比赛越来越卷了,而且py过于严重最后还是只能水个强网先锋,摸了。
2023-12-30
  目录