
CVE-2026-20251 — Splunk Secure Gateway jsonpickle deserialization RCE (CVSS 8.8) | ReactiveZero Security Research
Исследователь: 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)
Статус: Открыто — исправление доступно
Аутентифицированный пользователь с низкими привилегиями может добиться удаленного выполнения кода на хосте Splunk, сохранив сформированный документ в KV Store (коллекция mobile_alerts). Splunk Secure Gateway (SSG) позже читает этот документ и передает его напрямую в jsonpickle.decode(), восстанавливая произвольные объекты Python — в том числе те, которые выполняют команды ОС.
Вызов устанавливает safe=True, но этот флаг блокирует только устаревший путь eval py/repr. Теги py/reduce, py/object, py/type, py/function и py/module не затрагиваются и полностью эксплуатируемы.
Отдельный валидатор (check_alert_data_valid_json) предназначен для блокировки опасных тегов, но короткое замыкание происходит на первом распознанном ключе: любой документ, чей первый ключ верхнего уровня является разрешенным py/object (значение начинается с spacebridgeapp), немедленно возвращает True, оставляя соседние ключи — включая вредоносный гаджет py/reduce — полностью непроверенными.
| Ветвь | Исправлено в |
|---|---|
| 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).
Шаг 0 Злоумышленник с низкими привилегиями записывает подготовленный обходной
документ в коллекцию KV Store 'mobile_alerts' через Splunk REST API.
Не требуется роль администратора или power.
Шаг 1 SSG обрабатывает запрос на получение оповещений.
alerts_request_processor.py читает документ и передает его
check_alert_data_valid_json().
→ Валидатор видит "py/object": "spacebridgeapp..." как ПЕРВЫЙ ключ,
возвращает True и никогда не проверяет соседний ключ "notification",
который несет гаджет py/reduce.
Шаг 2 Теперь проверенный документ передается в
jsonpickle.decode(..., safe=True).
jsonpickle загружает класс (loadclass()) объекта Alert-приманки,
создает его экземпляр, затем перебирает его сохраненные атрибуты.
Когда он достигает значения "notification", срабатывает
_restore_reduce():
stage1 = f(*args) # unpickler.py ~line 526
safe=True не влияет на этот путь кода.
Результат Произвольное выполнение кода от имени учетной записи службы Splunk.
Требуется только действующий вход в Splunk с низкими привилегиями.
{
"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 SSG (загружается из /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Шаблон защитного программирования: Никогда не восстанавливайте произвольные типы из внешне-влияемых сохраненных данных. Замените jsonpickle.decode() на строгий, проверяемый по схеме парсер для входных данных, доступных атакующему, или предоставьте явный список разрешенных classes= для decode(). Убедитесь, что процедуры проверки полностью обходят вложенные структуры, а не выполняют короткое замыкание на первом распознанном ключе.
Эта же партия уведомлений включает CVE-2026-20253 (CVSS 9.8, неаутентифицированное создание произвольных файлов через конечную точку sidecar PostgreSQL). Эта уязвимость отсутствовала на протестированной сборке Splunk Enterprise 10.0.6 для macOS x86_64: компонент sidecar PostgreSQL не поставляется на этой платформе, не существует двоичных файлов или процессов sidecar, и не наблюдался соответствующий порт.
Это иллюстрирует важный принцип обеспечения безопасности: строка затронутой версии является необходимым, но недостаточным условием для эксплуатации. Проверка на уровне компонентов существенно меняет реальную картину риска.
| Поле | Значение |
|---|---|
| Ссылка на взаимодействие | 2026FO-SPLUNK-20251 |
| Тип тестирования |
ReactiveZero Security Research
| 3.8.67 |
| Splunk Enterprise | 10.0.7 / 10.2.4 / 10.4.0+ |
| Поддоказательство | Что показывает |
|---|
| A — Обход валидатора | check_alert_data_valid_json() возвращает True для обходного документа, никогда не проверяя гаджет py/reduce в соседнем значении |
| B — Выполнение py/reduce | jsonpickle.decode(..., safe=True) выполняет subprocess.check_output(['uname', '-a']), доказывая, что safe=True не блокирует этот путь кода |
| Верификация уязвимости методом белого ящика (статический анализ кода) |
| Дата | 26 июня 2026 |
| Область | Локальный исследовательский экземпляр Splunk Enterprise 10.0.6 (127.0.0.1:8089) |
| Классификация | Конфиденциально |