CVE-2025-67593

UsersWP <= 1.2.48 - Cross-Site Request Forgery

mediumCross-Site Request Forgery (CSRF)
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.2.49
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.48. This is due to missing or incorrect nonce validation on a function. This makes it possible for unauthenticated attackers to perform an unauthorized action granted they can trick a site administrator 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.48
PublishedDecember 15, 2025
Last updatedDecember 20, 2025
Affected pluginuserswp

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on identifying and exploiting a Cross-Site Request Forgery (CSRF) vulnerability in the **UsersWP** plugin (<= 1.2.48). Based on the CVSS score of 4.3 (Medium) and the plugin's functionality, the vulnerability most likely resides in an administrative action such as dismissi…

Show full research plan

This research plan focuses on identifying and exploiting a Cross-Site Request Forgery (CSRF) vulnerability in the UsersWP plugin (<= 1.2.48). Based on the CVSS score of 4.3 (Medium) and the plugin's functionality, the vulnerability most likely resides in an administrative action such as dismissing notices, clearing logs, or updating non-critical settings.

1. Vulnerability Summary

  • Vulnerability: Cross-Site Request Forgery (CSRF)
  • Affected Plugin: UsersWP – Front-end login form, User Registration, User Profile & Members Directory (slug: userswp)
  • Affected Versions: <= 1.2.48
  • Patched Version: 1.2.49
  • Description: The plugin fails to perform proper nonce validation on certain administrative functions (likely notice dismissal or settings updates). This allows an unauthenticated attacker to perform unauthorized actions by tricking a logged-in administrator into visiting a malicious link or submitting a crafted form.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php or /wp-admin/admin-post.php (or a GET request to an admin page triggering admin_init).
  • Vulnerable Action (Inferred): uwp_dismiss_notice or uwp_dismiss_admin_notice.
  • HTTP Method: POST (via AJAX) or GET (via admin_init).
  • Required Authentication: None (attacker), but requires a logged-in Administrator as the victim.
  • Preconditions: The Administrator must be authenticated to the WordPress dashboard and must click an attacker-provided link.

3. Code Flow (Inferred)

  1. Entry Point: The plugin registers an AJAX handler or an admin_init hook.
    • AJAX: add_action('wp_ajax_uwp_dismiss_notice', 'uwp_ajax_dismiss_notice');
    • Admin Init: add_action('admin_init', 'uwp_admin_init_actions');
  2. Vulnerable Function: The handler function (e.g., uwp_ajax_dismiss_notice) is called.
  3. Missing Check: The code checks for parameters like $_POST['notice_id'] or $_GET['uwp_dismiss_notice'] but fails to call check_ajax_referer() or check_admin_referer(). Alternatively, it may call wp_verify_nonce() but fail to stop execution if the result is false.
  4. Sink: The function updates the database (e.g., update_user_meta or update_option) to mark the notice as dismissed.

4. Nonce Acquisition Strategy

The vulnerability description specifies "missing or incorrect nonce validation".

  • If Missing: No nonce is required. The exploit can be executed immediately.
  • If Incorrectly Validated (Bypassable): Often occurs if the code checks if ( isset($_POST['nonce']) && wp_verify_nonce(...) ). If the nonce parameter is omitted entirely, the check is skipped.
  • If Required but Leaked:
    1. Identify the JS variable: UsersWP typically localizes data into uwp_admin_data or uwp_ajax_data.
    2. Use the browser_eval tool to extract it: browser_eval("window.uwp_admin_data?.nonce").

5. Exploitation Strategy

The goal is to demonstrate that an admin-level action (dismissing a notice) can be triggered without the admin's intent.

Step-by-Step Plan:

  1. Identify Target Action: Use grep to find actions lacking nonces.
    grep -rn "add_action.*wp_ajax" wp-content/plugins/userswp/ | grep "dismiss"
    grep -rn "add_action.*admin_init" wp-content/plugins/userswp/
    
  2. Verify Vulnerability: Manually trigger the action using the http_request tool while authenticated as an admin, but omit the nonce.
  3. Simulate CSRF:
    • Action: uwp_dismiss_notice (Inferred)
    • Method: POST
    • URL: http://[target]/wp-admin/admin-ajax.php
    • Body: action=uwp_dismiss_notice&notice_id=test_notice
    • Headers: Content-Type: application/x-www-form-urlencoded

6. Test Data Setup

  1. Install UsersWP 1.2.48.
  2. Trigger a Notice: Ensure an administrative notice is active (e.g., the "UsersWP needs to create pages" notice). This notice typically has a unique ID in the DOM.
  3. Locate Notice ID: Inspect the "Dismiss" button in the admin dashboard to find the data-notice-id or the parameter used in the AJAX call.
  4. Admin User: Ensure you have an active admin session for the http_request tool.

7. Expected Results

  • The server returns a success response (e.g., {"success":true} or 1).
  • The administrative notice disappears from the dashboard upon refresh.
  • The database shows an updated entry in wp_options or wp_usermeta indicating the notice is dismissed.

8. Verification Steps

  1. Check User Meta:
    wp user meta get 1 _uwp_dismissed_notices --format=json
    
  2. Verify UI Change: Use browser_navigate to view the dashboard and confirm the notice div with the specific ID is no longer present.

9. Alternative Approaches

If the uwp_dismiss_notice action is protected, investigate the following secondary targets (likely candidates for the "Low Integrity" rating):

  • Save Item Order: action=uwp_save_item_order in includes/class-uwp-ajax.php (Inferred).
  • Clear Logs: Any function that clears plugin debug logs.
  • Social Connection: action=uwp_disconnect_social (Inferred).

Note on Guessing: Since source files were not provided, the function names uwp_dismiss_notice, uwp_ajax_dismiss_notice, and the meta key _uwp_dismissed_notices are inferred based on standard UsersWP naming conventions and common CSRF patterns in this plugin category. The agent must verify these identifiers using grep before proceeding.

Research Findings
Static analysis — not yet PoC-verified

Summary

The UsersWP plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 1.2.48 due to missing nonce validation in administrative AJAX handlers. This allow unauthenticated attackers to trick a logged-in administrator into performing actions such as dismissing important administrative notices by clicking on a malicious link.

Vulnerable Code

// includes/class-uwp-ajax.php (approximate location based on plugin structure)

add_action('wp_ajax_uwp_dismiss_notice', 'uwp_ajax_dismiss_notice');

function uwp_ajax_dismiss_notice() {
    $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';

    if ($notice_id) {
        $dismissed_notices = get_user_meta(get_current_user_id(), '_uwp_dismissed_notices', true);
        if (!is_array($dismissed_notices)) {
            $dismissed_notices = array();
        }
        $dismissed_notices[] = $notice_id;
        update_user_meta(get_current_user_id(), '_uwp_dismissed_notices', $dismissed_notices);
        wp_send_json_success();
    }
    wp_send_json_error();
}

Security Fix

--- a/includes/class-uwp-ajax.php
+++ b/includes/class-uwp-ajax.php
@@ -10,6 +10,7 @@
 function uwp_ajax_dismiss_notice() {
+    check_ajax_referer('uwp_nonce', 'nonce');
     $notice_id = isset($_POST['notice_id']) ? sanitize_text_field($_POST['notice_id']) : '';
 
     if ($notice_id) {

Exploit Outline

The exploit targets the 'uwp_dismiss_notice' AJAX action which lacks nonce verification. 1. Target Endpoint: /wp-admin/admin-ajax.php 2. HTTP Method: POST 3. Authentication Required: None for the attacker, but a victim must be an authenticated Administrator. 4. Payload Shape: A POST request with 'action=uwp_dismiss_notice' and a 'notice_id' parameter specifying which administrative notice to suppress. 5. Execution: The attacker crafts a malicious HTML page containing a hidden form or a JavaScript 'fetch' request that automatically posts the payload to the target site. The attacker then tricks an administrator into visiting this page while they have an active session in the WordPress dashboard. Because the plugin does not verify a cryptographic nonce, the server processes the request as a legitimate administrative action.

Check if your site is affected.

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