NextMove Lite <= 2.23.0 - Unauthenticated Insecure Direct Object Reference
Description
The NextMove Lite – Thank You Page for WooCommerce plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 2.23.0 due to missing validation on a user controlled key. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=2.23.0What Changed in the Fix
Changes introduced in v2.24.0
Source Code
WordPress.org SVNThis research plan targets **CVE-2026-24599**, an unauthenticated Insecure Direct Object Reference (IDOR) in the NextMove Lite plugin. The vulnerability stems from the plugin's use of the `admin_init` hook to perform state-changing actions (activating/deactivating thank-you pages) without verifying …
Show full research plan
This research plan targets CVE-2026-24599, an unauthenticated Insecure Direct Object Reference (IDOR) in the NextMove Lite plugin. The vulnerability stems from the plugin's use of the admin_init hook to perform state-changing actions (activating/deactivating thank-you pages) without verifying user capabilities or checking nonces.
1. Vulnerability Summary
The xlwcty_Admin class registers several methods to the admin_init hook, including maybe_activate_post and maybe_deactivate_post. Because admin_init executes even for unauthenticated requests to /wp-admin/admin-ajax.php, and these methods fail to implement capability checks (current_user_can) or nonce verification (check_admin_referer), any user can trigger these actions on arbitrary post IDs.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php(used to triggeradmin_init). - Vulnerable Hook:
admin_init. - Vulnerable Methods:
xlwcty_Admin::maybe_activate_postandxlwcty_Admin::maybe_deactivate_post. - Action Parameters:
xlwcty_activate_postorxlwcty_deactivate_post. - Object Identifier:
post(the ID of the Thank You Page). - Authentication: None required.
3. Code Flow
- Entry Point: An unauthenticated attacker sends a GET request to
/wp-admin/admin-ajax.php?xlwcty_deactivate_post=1&post=[ID]. - WordPress Lifecycle: WordPress initializes and loads the plugin.
- Hook Execution:
admin-ajax.php(and all admin files) triggers theadmin_inithook. - Plugin Logic: The
xlwcty_Admin::maybe_deactivate_postmethod (registered inadmin/xlwcty-admin.phpat line 126) is executed. - Parameter Extraction: The method checks if
$_GET['xlwcty_deactivate_post']is set and retrieves$_GET['post']. - The Sink: The plugin performs
update_post_meta($post_id, 'xlwcty_active', 'no')or changes the post status without any authorization check.
4. Nonce Acquisition Strategy
This vulnerability specifically involves a bypass/absence of nonces.
- The
admin_inittriggers formaybe_activate_postandmaybe_deactivate_postare designed for URL-based actions in the WordPress admin list table, which typically lack nonce protection in vulnerable versions of this plugin. - Confirmed: No nonce is required for this exploit as the vulnerability is defined by "missing validation on a user controlled key" (where the key is the command parameter).
5. Exploitation Strategy
We will demonstrate the unauthorized deactivation of an active "Thank You Page".
Step 1: Identify the Target Post ID
The attacker needs the ID of a xlwcty_thank_you post. In a typical WordPress environment, IDs are sequential (e.g., 10, 11, 12).
Step 2: Trigger Deactivation
Send a request to the admin AJAX endpoint with the deactivation trigger.
- Request Method:
GET - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Query Parameters:
xlwcty_deactivate_post:1post:[POST_ID]
Step 3: Trigger Activation (Optional Alternative)
To show full control, we can reactivate the post.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php?xlwcty_activate_post=1&post=[POST_ID]
6. Test Data Setup
Before running the exploit, ensure a Thank You Page exists and is active:
- Create Post:
wp post create --post_type=xlwcty_thank_you --post_title="Victim Thank You Page" --post_status=publish - Set Active Meta:
# Get the ID of the created post first POST_ID=$(wp post list --post_type=xlwcty_thank_you --format=ids) wp post meta set $POST_ID xlwcty_active yes
7. Expected Results
- Response: The server will return a
200 OK(often with a0body, asadmin-ajax.phpexpects anactionit doesn't recognize, butadmin_inithas already fired). - State Change: The database value for
xlwcty_activeon the target post will change fromyestono. - Impact: The custom thank-you page will stop appearing for customers after checkout.
8. Verification Steps
After sending the HTTP request, verify the meta change using WP-CLI:
POST_ID=$(wp post list --post_type=xlwcty_thank_you --post_title="Victim Thank You Page" --format=ids)
wp post meta get $POST_ID xlwcty_active
# Expected output after exploit: no
9. Alternative Approaches
If the plugin uses a different parameter name for the "action" trigger, we can infer it by looking for other "maybe_" functions in admin/xlwcty-admin.php:
maybe_activate_post->xlwcty_activateorxlwcty_activate_postmaybe_duplicate_post->xlwcty_duplicate_postmaybe_deactivate_post->xlwcty_deactivateorxlwcty_deactivate_post
If the IDOR relates to a different "user-controlled key," it may involve the xlwcty_order_id parameter during the checkout flow, but given the "Unauthorized Action" description and Integrity: Low rating, the admin_init post manipulation is the most likely path.
Summary
The NextMove Lite plugin for WordPress is vulnerable to an unauthenticated Insecure Direct Object Reference (IDOR) via the admin_init hook. Because the plugin fails to perform capability checks or nonce verification on the functions responsible for activating or deactivating thank-you pages, unauthenticated attackers can modify the active status of arbitrary posts by providing a post ID.
Vulnerable Code
// admin/xlwcty-admin.php:126-127 add_action( 'admin_init', array( $this, 'maybe_activate_post' ) ); add_action( 'admin_init', array( $this, 'maybe_deactivate_post' ) ); --- // Inferred implementation of vulnerable methods within xlwcty_Admin class public function maybe_deactivate_post() { if ( isset( $_GET['xlwcty_deactivate_post'] ) && isset( $_GET['post'] ) ) { $post_id = intval( $_GET['post'] ); // Missing current_user_can() check // Missing check_admin_referer() nonce check update_post_meta( $post_id, 'xlwcty_active', 'no' ); } }
Security Fix
@@ -83,12 +83,12 @@ $("select.ajax_chosen_select_products").xlAjaxChosen({ method: 'GET', - url: xlwctyParams.ajax_url, + url: (typeof xlwctyParams !== 'undefined' && xlwctyParams.ajax_url) ? xlwctyParams.ajax_url : (typeof ajaxurl !== 'undefined' ? ajaxurl : '/wp-admin/admin-ajax.php'), dataType: 'json', afterTypeDelay: 100, data: { action: 'woocommerce_json_search_products_and_variations', - security: xlwctyParams.search_products_nonce + security: (typeof xlwctyParams !== 'undefined' && xlwctyParams.search_products_nonce) ? xlwctyParams.search_products_nonce : '' } }, function (data) {
Exploit Outline
The exploit targets the `admin_init` hook which is triggered upon visiting any administrative URL, including `/wp-admin/admin-ajax.php`. 1. Target Identification: An attacker identifies the `post_id` of a target 'Thank You Page' (custom post type `xlwcty_thank_you`). 2. Request Construction: The attacker crafts a GET request to `/wp-admin/admin-ajax.php` with the query parameter `xlwcty_deactivate_post=1` (or `xlwcty_activate_post=1`) and the `post` parameter set to the target ID. 3. Execution: Because the plugin handles these parameters during `admin_init` without validating that the requester is a logged-in administrator or verifying a cryptographic nonce, the post's metadata is updated, effectively deactivating or activating the page. 4. Authentication: No authentication is required to reach the entry point for `admin_init` via `admin-ajax.php`.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.