CVE-2026-3830

Product Filter for WooCommerce by WBW < 3.1.3 - 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
3.1.3
Patched in
44d
Time to patch

Description

The Product Filter for WooCommerce by WBW plugin for WordPress is vulnerable to SQL Injection in versions up to 3.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 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<3.1.3
PublishedMarch 23, 2026
Last updatedMay 5, 2026
Affected pluginwoo-product-filter

What Changed in the Fix

Changes introduced in v3.1.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This analysis targets an unauthenticated SQL injection vulnerability in the **Product Filter for WooCommerce by WBW** plugin (version < 3.1.3). The vulnerability stems from improper sanitization and lack of query preparation when processing filter parameters in the frontend AJAX request. ### 1. Vul…

Show full research plan

This analysis targets an unauthenticated SQL injection vulnerability in the Product Filter for WooCommerce by WBW plugin (version < 3.1.3). The vulnerability stems from improper sanitization and lack of query preparation when processing filter parameters in the frontend AJAX request.

1. Vulnerability Summary

The vulnerability exists in the WoofiltersControllerWpf class within the modules/woofilters/controller.php file. Specifically, the filtersFrontend() method processes user-supplied JSON data from the filtersDataBackend and queryvars parameters. This data is passed into SQL-building functions that utilize the _prepareTextLikeSearch() method, which performs direct string concatenation of user input into a SQL LIKE clause without using $wpdb->prepare() or sufficient escaping.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: wpf_ajax
  • Query Parameters: pl=wpf, mod=woofilters, task=filtersFrontend
  • POST Parameters:
    • filtersDataBackend: A JSON-encoded array containing filter configurations.
    • queryvars: A JSON-encoded object containing WooCommerce query arguments.
  • Authentication: None required (Unauthenticated).
  • Preconditions: At least one product must exist in WooCommerce for the filter logic to execute its database queries.

3. Code Flow

  1. Entry: A request is sent to admin-ajax.php with action=wpf_ajax.
  2. Routing: FrameWpf::parseRoute() (in classes/frame.php) extracts mod=woofilters and task=filtersFrontend.
  3. Execution: FrameWpf::exec() calls WoofiltersControllerWpf::filtersFrontend().
  4. Processing: filtersFrontend() decodes the filtersDataBackend JSON.
  5. Vulnerable Sink: The controller logic (via createArgsForFiltering) processes search-type filters using _prepareTextLikeSearch($val) (line 15 of modules/woofilters/controller.php):
    protected function _prepareTextLikeSearch( $val ) {
        $query = '(title LIKE "%' . $val . '%"'; // <--- SQL INJECTION POINT
        if ( is_numeric($val) ) {
            $query .= ' OR id LIKE "%' . (int) $val . '%"';
        }
        $query .= ')';
        return $query;
    }
    
  6. Query Execution: The resulting unescaped string is added to the model's WHERE clause via $model->addWhere(array('additionalCondition' => $query)) and executed against the database.

4. Nonce Acquisition Strategy

While filtersFrontend does not strictly enforce a nonce check (making it unauthenticated), the plugin often localizes a nonce for other frontend features. If an environment requires a nonce for all wpf_ajax actions, use the following:

  1. Shortcode: The plugin uses [wpf-filters id=...].
  2. Setup: Create a filter and a page containing its shortcode.
    wp post create --post_type=wpf_filters --post_title="Exploit Filter" --post_status=publish
    # Note the ID of the new post (e.g., 123)
    wp post create --post_type=page --post_title="Filter Page" --post_content="[wpf-filters id=123]" --post_status=publish
    
  3. Extraction: Use browser_navigate to the new page and browser_eval to extract the localized settings:
    // WBW typically localizes data into a variable named after the plugin/module
    // Look for 'wpfNonce' in the localized object
    window.wpfFrontendPage?.nonce || window.wpfMainWrapper?.wpfNonce
    

5. Exploitation Strategy

We will use a time-based blind SQL injection payload within the filtersDataBackend JSON structure, targeting the search filter logic.

**HTTP Request (via `http_

Research Findings
Static analysis — not yet PoC-verified

Summary

The Product Filter for WooCommerce by WBW plugin is vulnerable to unauthenticated SQL injection due to the improper concatenation of user-supplied data into SQL queries. Attackers can exploit this via the filtersFrontend AJAX action to extract sensitive database information or perform time-based blind attacks.

Vulnerable Code

// modules/woofilters/controller.php around line 15
protected function _prepareTextLikeSearch( $val ) {
    $query = '(title LIKE "%' . $val . '%"';
    if ( is_numeric($val) ) {
        $query .= ' OR id LIKE "%' . (int) $val . '%"';
    }
    $query .= ')';
    return $query;
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/woo-product-filter/3.1.2/classes/frame.php /home/deploy/wp-safety.org/data/plugin-versions/woo-product-filter/3.1.3/classes/frame.php
--- /home/deploy/wp-safety.org/data/plugin-versions/woo-product-filter/3.1.2/classes/frame.php	2025-11-28 17:20:46.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/woo-product-filter/3.1.3/classes/frame.php	2026-03-20 11:01:42.000000000 +0000
@@ -406,14 +408,19 @@
 
 	/**
 	 * _doExec.
+	 *
+	 * @version 3.1.3
 	 */
 	protected function _doExec() {
 		$mod = $this->getModule($this->_mod);
 		if ($mod && $this->checkPermissions($this->_mod, $this->_action)) {
 			switch (ReqWpf::getVar('reqType')) {
 				case 'ajax':
-					add_action('wp_ajax_'        . $this->_action, array($mod->getController(), $this->_action));
-					add_action('wp_ajax_nopriv_' . $this->_action, array($mod->getController(), $this->_action));
+					add_action('wp_ajax_' . $this->_action, array($mod->getController(), $this->_action));
+					$noprivActions = array( 'filtersFrontend', 'getTaxonomyTerms' );
+					if ( in_array( $this->_action, $noprivActions ) ) {
+						add_action('wp_ajax_nopriv_' . $this->_action, array($mod->getController(), $this->_action));
+					}
 					break;
 				default:
 					$this->_res = $mod->exec($this->_action);

Exploit Outline

The exploit targets the unauthenticated AJAX endpoint 'wpf_ajax' with the 'filtersFrontend' task. An attacker sends a POST request to '/wp-admin/admin-ajax.php' with the parameter 'pl=wpf', 'mod=woofilters', and 'task=filtersFrontend'. The payload is embedded within the 'filtersDataBackend' JSON parameter, specifically within a search-type filter value. Because the plugin concatenates this value directly into a LIKE clause in the '_prepareTextLikeSearch' method without using $wpdb->prepare() or escaping, an attacker can use a payload like '") OR SLEEP(5)-- -' to trigger a time-based blind SQL injection.

Check if your site is affected.

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