
Exploit de prueba de concepto para CVE-2026-78122, que demuestra la exfiltración del sistema de archivos del contenedor y de variables de entorno a través de las reglas de acceso laxas de docker-socket-proxy, junto con una configuración parcheada de HAProxy.
Tecnativa docker-socket-proxy ≤ 0.5.0 — Granularidad insuficiente del control de acceso (CWE-1220)
CVSS 4.0: 8.3 (Alta) — CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N
El vector de ataque es Adyacente (
AV:A): el atacante necesita acceso de red local/adyacente al proxy — que es exactamente por lo que mantenerlo fuera de cualquier interfaz enrutable forma parte de la mitigación.
docker-socket-proxy es un front-end de HAProxy para el socket de Docker cuyo
propósito es otorgar acceso acotado y con mínimos privilegios a la API de
Docker. La receta canónica "segura y de solo lectura" que usan los operadores es:
CONTAINERS=1 # allow listing/inspecting containers
POST=0 # deny everything that mutates state
# every other flag left at its default (0)
Los operadores creen razonablemente que esto produce metadatos de contenedores de solo lectura. No es así.
En haproxy.cfg
todo el espacio de nombres /containers está controlado por una única regla de prefijo no granular:
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers } { env(CONTAINERS) -m bool }
Esa regex coincide con todas las subrutas GET bajo /containers, incluidos
los endpoints de lectura sensibles que nunca debieron formar parte de "listar contenedores".
Como todas son GET, la protección POST=0 no hace nada para detenerlas:
Efecto neto: con la postura "endurecida" CONTAINERS=1, POST=0, cualquiera que
pueda alcanzar el proxy puede extraer secretos y exfiltrar el sistema de archivos
completo de todos los contenedores del host.
lab/ vulnerable docker-socket-proxy v0.5.0 + a victim container with planted secrets
exploit/ exploit.sh — end-to-end data-exfiltration PoC
mitigation/ patched haproxy.cfg + compose that denies the sensitive sub-paths
verify.sh one command: stand up both, exploit, print a before/after table
teardown.sh stop everything
loot/ exploit output lands here
Requiere Docker + Docker Compose y un shell POSIX (Git Bash en Windows funciona).
./verify.sh
O paso a paso:
docker compose -f lab/docker-compose.yml up -d # vulnerable proxy on 127.0.0.1:2375
bash exploit/exploit.sh http://127.0.0.1:2375 # loot lands in ./loot
El proxy está vinculado únicamente a
127.0.0.1. Nunca expongas un proxy de socket de Docker en una interfaz enrutable.
[+] POST /containers/create -> 403 Forbidden (operator believes they are safe)
Leaked environment variables:
STRIPE_API_KEY=sk_live_FAKE_0000000000000000
DB_PASSWORD=hunter2-from-container-env
[+] Pulled /etc/passwd via /archive
[+] Stole /run/secrets/aws.env via /archive
[+] Exported entire filesystem (8,095,232 bytes) via /export
[+] Retrieved process table via /top and logs via /logs
Cada elemento anterior se obtuvo con POST=0 aún en vigor.
La solución real: actualizar a la versión parcheada (seguimiento en
issue #182 /
PR #183) y dejar de
confiar en que CONTAINERS=1 por sí solo sea "solo lectura".
Este repositorio también incluye una configuración endurecida de tipo drop-in
(mitigation/haproxy.patched.cfg) que añade
reglas deny explícitas para las subrutas peligrosas antes de la regla
/containers general, cada una reactivable mediante una bandera dedicada
(ALLOW_ARCHIVE, ALLOW_EXPORT, ALLOW_LOGS, ALLOW_TOP):
http-request deny if { ... /containers/[..]/archive } ! { env(ALLOW_ARCHIVE) -m bool }
http-request deny if { ... /containers/[..]/export } ! { env(ALLOW_EXPORT) -m bool }
http-request deny if { ... /containers/[..]/logs } ! { env(ALLOW_LOGS) -m bool }
http-request deny if { ... /containers/[..]/top } ! { env(ALLOW_TOP) -m bool }
Verificado antes/después (salida de verify.sh) — misma postura CONTAINERS=1, POST=0:
Las operaciones legítimas de listar/inspeccionar siguen funcionando; las primitivas de exfiltración están bloqueadas.
Operativamente, además: mantén el proxy fuera de cualquier red enrutable, monta el socket de Docker como solo lectura y aplica el mínimo privilegio (habilita solo las banderas exactas que un consumidor necesita).
Solo para pruebas de seguridad autorizadas y fines educativos. El laboratorio se ejecuta íntegramente en tu propio host contra contenedores que tú creaste.
| Endpoint (GET) | Lo que filtra |
|---|
/containers/{id}/archive?path=… | Lectura arbitraria de archivos desde cualquier contenedor |
/containers/{id}/export | Sistema de archivos completo del contenedor como tar |
/containers/{id}/logs | stdout/stderr del contenedor |
/containers/{id}/top | Lista de procesos con argv completo (puede contener credenciales) |
/containers/{id}/json | Configuración completa, incl. variables de entorno |
| GET endpoint | Vulnerable (:2375) | Mitigado (:2376) |
|---|
/containers/json (list) | 200 | 200 |
/containers/{id}/json (inspect) | 200 | 200 |
/containers/{id}/archive | 200 | 403 |
/containers/{id}/export | 200 | 403 |
/containers/{id}/logs | 200 | 403 |
/containers/{id}/top | 200 | 403 |