
PoC para CVE-2026-44848: falta de autorización en Portainer en los endpoints de plugins de Docker -> RCE en el host (GHSA-rrmm-9v76-h3p4). Python solo con stdlib.
Prueba de concepto de CVE-2026-44848, una vulnerabilidad de falta de autenticación (CWE-862) en Portainer que permite a un usuario no administrador con acceso al endpoint de Docker realizar operaciones privilegiadas de plugins de Docker → RCE completo en el host.
Aviso de seguridad de GitHub: GHSA-rrmm-9v76-h3p4 · CVSS 9.4 (Crítico).
Portainer aplica Control de Acceso Basado en Roles (RBAC) sobre la API de Docker mediante el proxy de
solicitudes a través de manejadores por recurso que aplican comprobaciones de autorización. Los endpoints
de gestión de plugins de Docker (/plugins/*) no estaban registrados con un manejador, por lo que
la capa de autorización nunca se ejecuta para ellos. Como resultado, un Usuario Estándar (Rol 2) — o cualquier
rol con acceso a nivel de endpoint — puede llamar a operaciones privilegiadas de plugins directamente contra
el daemon de Docker subyacente:
POST /plugins/pull — extraer un plugin arbitrario de cualquier registroCAP_SYS_ADMIN y montajes de rutas del hostPOST /plugins/{name}/enable — Docker ejecuta el plugin como root en el host con esas capacidades → acceso completo al sistema de archivos del host y equivalente a root en el host de Docker>= 2.33.0, < 2.33.8>= 2.39.0, < 2.39.2>= 2.40.0, < 2.41.0La primitiva central del fallo, reproducible de forma segura: un usuario estándar (no administrador) puede alcanzar
la API de Docker privilegiada /plugins/* a través del proxy de Portainer sin autorización.
Lo hace de extremo a extremo contra una instancia real y vulnerable de Portainer:
POST /api/users/admin/init (tolera 409 y recurre al inicio de sesión).bob, Rol 2), tolerando 409 al restablecer su contraseña.POST /api/endpoints si no existe ninguno) y concede a bob acceso mediante
PUT /api/endpoints/{id} UserAccessPolicies.bob (el usuario no administrador) y llama a
GET /api/endpoints/1/docker/plugins con el token de bob.# Defaults: https://localhost:9444, random admin password
python3 portainer_plugin_poc.py
# Explicit target + admin password + command
python3 portainer_plugin_poc.py --url https://localhost:9444 --admin-pass 'P@ssw0rd!' --command "id; hostname"
# Write a JSON summary
python3 portainer_plugin_poc.py --url https://localhost:9444 --output out.json
python3 portainer_plugin_poc.py --help
Requiere solo la biblioteca estándar de Python 3. La verificación TLS está deshabilitada (certificados de laboratorio autofirmados).
docker run -d --name portainer-lab-cve44848 \
-p 127.0.0.1:9444:9443 \
-v /var/run/docker.sock:/var/run/docker.sock \
portainer/portainer-ce:2.39.1 # vulnerable
AUTH-BYPASS CONFIRMED: standard user reached /plugins (HTTP 200)
=> PASS (missing auth / host-RCE primitive confirmed)
Solo para investigación y pruebas de seguridad autorizadas. El paso habilitador (POST /plugins/*)
puede otorgar root en el host; este PoC se limita a demostrar el bypass de autorización y
no habilita un plugin destructivo/malicioso. Úsalo solo contra sistemas que poseas o estés
autorizado a probar.