
Write-up y prueba de concepto para CVE-2026-94609, una vulnerabilidad de escalada de privilegios en authentik que permite a usuarios con add_user_to_group unirse a grupos de superusuario a través de la API de Groups.
Análisis y prueba de concepto de una vulnerabilidad de escalada de privilegios en goauthentik/authentik, corregida en 2026.2.7 / 2026.5.7 / 2026.8.2 y asignada como CVE-2026-94609 (GHSA-h6c5-mpvq-j4jc).
Fui uno de los reporteros acreditados en este aviso (
@anthonyk2923— crédito aceptado). Este repositorio documenta la ruta de código específica que encontré y reporté de forma independiente, además de una PoC. El aviso publicado cubre el problema completo y más amplio (jerarquía de grupos + asignación de roles), que fue reportado por múltiples investigadores independientes y corregido en conjunto.
Una cuenta con solo un permiso rutinario y comúnmente delegado —
authentik_core.add_user_to_group (añadir miembros a un grupo) — podía añadirse
a sí misma o a cualquier otro usuario directamente en un grupo existente marcado
como is_superuser=True a través de la API estándar de Groups, y ese usuario se
convertía inmediatamente en un superusuario real de authentik. Esto ocurría sin
poseer nunca authentik_core.enable_group_superuser, el permiso diseñado
específicamente para controlar esta acción exacta.
authentik ya había corregido la versión espejo de este fallo en el lado del Usuario (asignar grupos de superusuario a un usuario). La comprobación equivalente faltaba en el lado del Grupo (asignar usuarios a un grupo de superusuario).
authentik modela dos permisos RBAC intencionadamente separados para la gestión de la pertenencia a grupos:
authentik_core.add_user_to_group — pensado para la gestión rutinaria y
delegada de miembros (por ejemplo, un rol de "helpdesk" o "líder de equipo" que gestiona
las plantillas cotidianas de los equipos).authentik_core.enable_group_superuser — pensado para controlar el acto mucho más
sensible de conceder o unirse a un grupo cuyo flag is_superuser=True convierte a
todos los miembros en superusuarios completos de authentik.La separación existe precisamente para que una organización pueda delegar la gestión ordinaria de grupos de forma amplia, sin otorgar también la capacidad de crear superusuarios.
authentik ya había corregido esta misma confusión una vez, en el lado del Usuario
de la relación (PATCH /api/v3/core/users/{pk}/ mediante
UserSerializer.validate_groups()), registrado como
GHSA-h6x7-hjjc-wjc9 / CVE-2026-40172
(CVSS 8.1, Alta). La corrección añadió:
# authentik/core/api/users.py (fixed)
def validate_groups(self, groups: list) -> list:
"""Require enable_group_superuser permission when adding a user to a superuser group."""
...
for group in groups:
if not group.is_superuser:
continue
if group in current_groups:
continue
if not request.user.has_perm("authentik_core.enable_group_superuser"):
raise ValidationError(...)
La ruta de código simétrica en el lado del Grupo — añadir miembros a un grupo, en lugar de añadir grupos a un usuario — nunca recibió la comprobación equivalente.
GroupSerializer.validate_users() en authentik/core/api/groups.py solo
comprobaba add_user_to_group, y nunca inspeccionaba self.instance.is_superuser
en absoluto:
# authentik/core/api/groups.py (vulnerable)
def validate_users(self, users: list) -> list:
"""Require add_user_to_group permission when adding new members via group PATCH."""
request: Request = self.context.get("request", None)
if not request:
return users
if not self.instance:
return users
current_user_pks = set(self.instance.users.values_list("pk", flat=True))
new_users = [u for u in users if u not in current_user_pks]
if not new_users:
return users
has_perm = request.user.has_perm(
"authentik_core.add_user_to_group"
) or request.user.has_perm("authentik_core.add_user_to_group", self.instance)
if not has_perm:
raise ValidationError(_("User does not have permission to add members to this group."))
return users
No hay ninguna guarda if self.instance.is_superuser: require enable_group_superuser
en ningún lugar de este método. Como resultado:
Cualquier llamante que posea
add_user_to_group— ya sea de forma global o con alcance de objeto sobre un único grupo de superusuario específico — puede hacerPATCHal campousersde ese grupo para añadir cualquier usuario (incluido él mismo), y ese usuario se convierte en un superusuario real de authentik de inmediato.
add_user_to_group es exactamente el tipo de permiso que el propio modelo RBAC de
granularidad fina de authentik anima a delegar de forma amplia e independiente de
enable_group_superuser — por ejemplo, a un rol personalizado de "gestor de usuarios" o
"helpdesk". La prueba existente
authentik/core/tests/test_groups_api.py::test_patch_users_with_global_perm
ya demostraba que una concesión global de add_user_to_group (sin ningún alcance
de objeto) es suficiente para hacer PATCH de miembros en cualquier grupo de la
instancia — esa prueba simplemente nunca ejercitó un grupo con
is_superuser=True, por lo que el hueco pasó desapercibido.
Este es el mismo fallo subyacente que el aviso publicado describe de forma más amplia: los grupos forman una jerarquía y el estado de superusuario se hereda de cualquier grupo padre, pero las comprobaciones que controlan quién puede cambiar la pertenencia a grupos, la relación de parentesco entre grupos y la asignación de roles o bien no buscaban el estado de superusuario en absoluto, o solo miraban el flag propio del grupo en lugar del efectivo (heredado).
Escalada de privilegios completa desde "cualquier cuenta que posea un permiso rutinario y comúnmente delegado de pertenencia a grupos" hasta "superusuario completo de authentik" — que controla cada inquilino, el SSO de cada aplicación descendente, todas las cuentas de usuario, todos los secretos/certificados gestionados por authentik y toda la configuración de la instancia.
CVE-2026-94609.py
Una PoC autónoma al estilo de cliente HTTP en vivo. Toma una URL objetivo y un token de API
para una cuenta de bajo privilegio (que solo posee add_user_to_group), y
opcionalmente un grupo objetivo/víctima, y luego intenta la misma escalada a través
de la API real:
# Check your own deployment for the bug, no mutation:
python3 exploit_CVE-2026-94609.py --url https://authentik.example.com \
--token <low-priv-api-token> --group "superadmins" --check-only
# List superuser groups reachable to this token:
python3 exploit_CVE-2026-94609.py --url https://authentik.example.com \
--token <low-priv-api-token> --list-groups
# Attempt the actual escalation (self, or a named/PK victim):
python3 exploit_CVE-2026-94609.py --url https://authentik.example.com \
--token <low-priv-api-token> --group "superadmins" --victim jdoe
Solo requiere pip install requests. Solo para uso autorizado — ejecútalo
contra instancias para las que estés explícitamente autorizado a probar.
| Rama | Afectadas | Parcheadas |
|---|---|---|
| 2026.2.x | ≤ 2026.2.6 | 2026.2.7 |
| 2026.5.x | ≤ 2026.5.6 | 2026.5.7 |
| 2026.8.x | ≤ 2026.8.1 | 2026.8.2 |
Actualiza a una versión parcheada. Si no puedes actualizar de inmediato, según el workaround del aviso oficial: restringe los permisos para crear/modificar grupos, modificar usuarios y añadir usuarios a grupos de modo que solo los administradores completos los posean — no delegues ninguno de estos a roles no administradores hasta que se parchee.
Este análisis y la PoC se proporcionan con fines educativos y de investigación en seguridad defensiva. Consulta la licencia propia de authentik (MIT) para el proyecto subyacente.
| Clase de vulnerabilidad | Escalada de privilegios / Control de acceso inadecuado |
| CWE | CWE-269 (Gestión inadecuada de privilegios), CWE-863 (Autorización incorrecta) |
| CVSS 3.1 | AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — Alta |
| Afectados | authentik ≤ 2026.2.6, ≤ 2026.5.6, ≤ 2026.8.1 |
| Corregido en | 2026.2.7, 2026.5.7, 2026.8.2 |
| Ruta accesible | PATCH /api/v3/core/groups/{group_uuid}/ |
| Causa raíz | GroupSerializer.validate_users() nunca comprobaba enable_group_superuser |