
Write-up e proof-of-concept per CVE-2026-94609, una vulnerabilità di privilege escalation in authentik che consente agli utenti con add_user_to_group di unirsi a gruppi superuser tramite la Groups API.
Write-up e proof-of-concept per una vulnerabilità di escalatione di privilegi in goauthentik/authentik, corretta in 2026.2.7 / 2026.5.7 / 2026.8.2 e assegnata CVE-2026-94609 (GHSA-h6c5-mpvq-j4jc).
Sono stato uno dei segnalatori accreditati in questo advisory (
@anthonyk2923— credito accettato). Questo repo documenta lo specifico percorso di codice che ho individuato e segnalato in modo indipendente, più un PoC. L'advisory pubblicato copre il problema completo e più ampio (gerarchia dei gruppi + assegnazione dei ruoli), che è stato segnalato da più ricercatori indipendenti e corretto insieme.
Un account con solo un permesso di routine, comunemente delegato —
authentik_core.add_user_to_group (aggiungere membri a un gruppo) — poteva aggiungere
se stesso o qualsiasi altro utente direttamente in un gruppo esistente contrassegnato
is_superuser=True tramite la normale Groups API, e quell'utente diventava
immediatamente un vero superuser di authentik. Ciò accadeva senza mai possedere
authentik_core.enable_group_superuser, il permesso specificamente
progettato per controllare questa esatta azione.
authentik aveva già corretto la versione speculare di questo bug sul lato User (assegnare gruppi superuser a un utente). Il controllo equivalente mancava sul lato Group (assegnare utenti a un gruppo superuser).
authentik modella due permessi RBAC intenzionalmente separati per la gestione dell'appartenenza ai gruppi:
authentik_core.add_user_to_group — pensato per la gestione di routine e delegata
dell'appartenenza (ad es. un ruolo "helpdesk" o "team lead" che gestisce
i roster quotidiani del team).authentik_core.enable_group_superuser — pensato per controllare l'atto ben più
sensibile di concedere o entrare in un gruppo il cui flag is_superuser=True
rende ogni membro un superuser completo di authentik.La separazione esiste proprio per consentire a un'organizzazione di delegare ampiamente la gestione ordinaria dei gruppi, senza anche concedere la capacità di creare superuser.
authentik aveva già corretto questa esatta confusione una volta, sul lato User
della relazione (PATCH /api/v3/core/users/{pk}/ tramite
UserSerializer.validate_groups()), tracciata come
GHSA-h6x7-hjjc-wjc9 / CVE-2026-40172
(CVSS 8.1, High). La correzione ha aggiunto:
# 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(...)
Il percorso di codice simmetrico sul lato Group — aggiungere membri a un gruppo, piuttosto che aggiungere gruppi a un utente — non ha mai ricevuto il controllo equivalente.
GroupSerializer.validate_users() in authentik/core/api/groups.py verificava solo
add_user_to_group, e non ispezionava mai self.instance.is_superuser
del tutto:
# 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
Non c'è alcuna guardia if self.instance.is_superuser: require enable_group_superuser
da nessuna parte in questo metodo. Di conseguenza:
Qualsiasi chiamante che possiede
add_user_to_group— globalmente, o con scope sull'oggetto di un solo specifico gruppo superuser — può eseguirePATCHsul campousersdi quel gruppo per aggiungere qualsiasi utente (incluso se stesso), e quell'utente diventa immediatamente un vero superuser di authentik.
add_user_to_group è esattamente il tipo di permesso che il modello RBAC a grana fine di authentik
incoraggia a delegare ampiamente e indipendentemente da
enable_group_superuser — ad es. a un ruolo personalizzato "user manager" o "helpdesk". Il test
esistente
authentik/core/tests/test_groups_api.py::test_patch_users_with_global_perm
dimostrava già che una concessione globale di add_user_to_group (nessuno scope
sull'oggetto) è sufficiente per eseguire PATCH dei membri in qualsiasi gruppo
dell'istanza — quel test semplicemente non esercitava mai un gruppo con
is_superuser=True, quindi la lacuna è rimasta non rilevata.
Questo è lo stesso difetto di fondo che l'advisory pubblicato descrive in modo più ampio: i gruppi formano una gerarchia e lo stato di superuser è ereditato da qualsiasi gruppo genitore, ma i controlli che regolano chi può modificare l'appartenenza ai gruppi, la genitorialità dei gruppi e l'assegnazione dei ruoli o non cercavano affatto lo stato di superuser, o guardavano solo il flag del gruppo stesso piuttosto che quello effettivo (ereditato).
Escalatione di privilegi completa da "qualsiasi account che possiede un permesso di routine, comunemente delegato, di appartenenza ai gruppi" a "superuser completo di authentik" — che controlla ogni tenant, l'SSO di ogni applicazione a valle, ogni account utente, tutti i segreti/certificati gestiti da authentik e l'intera configurazione dell'istanza.
CVE-2026-94609.py
Un PoC autonomo in stile client HTTP live. Prende un URL di destinazione e un token API
per un account a bassi privilegi (che possiede solo add_user_to_group), e
opzionalmente un gruppo di destinazione/vittima, quindi tenta la stessa escalation tramite
l'API reale:
# 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
Richiede solo pip install requests. Solo uso autorizzato — eseguilo
contro istanze che sei esplicitamente autorizzato a testare.
| Branch | Affette | Corrette |
|---|---|---|
| 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 |
Aggiorna a una versione corretta. Se non puoi aggiornare immediatamente, secondo la workaround dell'advisory ufficiale: limita i permessi di creare/modificare gruppi, modificare utenti e aggiungere utenti ai gruppi in modo che solo gli amministratori completi li possiedano — non delegare nessuno di questi a ruoli non-admin finché non è corretta.
Questo write-up e il PoC sono forniti per scopi educativi e di ricerca sulla sicurezza difensiva. Vedi la licenza di authentik (MIT) per il progetto sottostante.
| Classe di vulnerabilità | Escalatione di privilegi / Controllo degli accessi improprio |
| CWE | CWE-269 (Gestione impropria dei privilegi), CWE-863 (Autorizzazione errata) |
| CVSS 3.1 | AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — High |
| Affette | authentik ≤ 2026.2.6, ≤ 2026.5.6, ≤ 2026.8.1 |
| Corrette in | 2026.2.7, 2026.5.7, 2026.8.2 |
| Route raggiungibile | PATCH /api/v3/core/groups/{group_uuid}/ |
| Causa principale | GroupSerializer.validate_users() non ha mai verificato enable_group_superuser |