CVE-2026-32450

Active Products Tables for WooCommerce. Use constructor to create tables  <= 1.0.7 - Authenticated (Contributor+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
1.0.8
Patched in
10d
Time to patch

Description

The Active Products Tables for WooCommerce. Use constructor to create tables  plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.0.7 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.7
PublishedMarch 10, 2026
Last updatedMarch 19, 2026

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-32450 (Active Products Tables for WooCommerce) ## 1. Vulnerability Summary The **Active Products Tables for WooCommerce** (slug: `profit-products-tables-for-woocommerce`) plugin is vulnerable to **Stored Cross-Site Scripting (XSS)** in versions up to 1.0.7. Th…

Show full research plan

Exploitation Research Plan: CVE-2026-32450 (Active Products Tables for WooCommerce)

1. Vulnerability Summary

The Active Products Tables for WooCommerce (slug: profit-products-tables-for-woocommerce) plugin is vulnerable to Stored Cross-Site Scripting (XSS) in versions up to 1.0.7. The vulnerability exists because the plugin's "Constructor" feature, which allows users to build and save custom product tables, fails to sanitize user-supplied input when saving table configurations and fails to escape that data when rendering the table via a shortcode.

This allows an authenticated attacker with Contributor-level permissions or higher to inject malicious JavaScript into a table's configuration (e.g., in column titles or CSS classes). When the table is displayed on the frontend via a shortcode, the script executes in the context of any user viewing the page, including administrators.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: woot_save_table_settings (inferred based on plugin architecture) or a similar action associated with the "Constructor" tab.
  • Vulnerable Parameters: Table configuration fields, specifically title, columns, or css_classes within the JSON-encoded table settings.
  • Authentication: Authenticated, Contributor-level access (PR:L).
  • Preconditions: The plugin must be active, and WooCommerce must be installed (as it's a WooCommerce extension).

3. Code Flow (Inferred)

  1. Entry Point: The attacker sends a POST request to admin-ajax.php with the action woot_save_table_settings.
  2. Processing: The plugin's AJAX handler (likely inside a class handling "Constructor" settings) receives the table configuration.
  3. Sink (Storage): The handler uses update_option() or update_post_meta() to save the configuration array/object. It likely lacks sanitization (like sanitize_text_field or wp_kses).
  4. Retrieval: A user (or the attacker) places a shortcode such as [woot id="123"] on a page.
  5. Sink (Output): The shortcode callback retrieves the stored configuration. While iterating through columns to render the table headers or cells, it outputs the stored values directly using echo or similar functions without esc_html() or esc_attr().

4. Nonce Acquisition Strategy

The plugin typically enqueues its settings scripts in the WordPress admin dashboard. The nonces and configuration are localized into a JavaScript object.

  1. Identify Script Localization: Look for wp_localize_script calls in the source. Common variable names for this plugin family: woot_vars, woot_constructor_vars, or woot_admin_vars.
  2. Target Page: Navigate to the plugin's "Constructor" page (usually wp-admin/admin.php?page=woot&tab=constructor).
  3. Extraction:
    • Use browser_navigate to reach the admin page as a Contributor.
    • Use browser_eval to extract the nonce:
      window.woot_vars?.nonce || window.woot_constructor_vars?.nonce || document.querySelector('input[name="woot_nonce"]')?.value
      
  4. Verification: Check if the action used for wp_create_nonce matches the one checked in the AJAX handler (likely woot_save_table_settings).

5. Exploitation Strategy

  1. Authentication: Log in as a user with the Contributor role.
  2. Identify Table ID: Create a dummy table via the UI or identify the ID of an existing table.
  3. Craft Payload: Create a JSON object representing the table settings where a column title contains the XSS payload.
    • Payload: "><script>alert(document.cookie)</script>
  4. Execute AJAX Request: Send the malicious configuration via http_request.
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Method: POST
    • Body (URL-encoded):
      • action=woot_save_table_settings
      • woot_nonce=[EXTRACTED_NONCE]
      • table_id=1 (or the target ID)
      • settings=[JSON_PAYLOAD_CONTAINING_XSS]
  5. Trigger Execution:
    • Create a new post/page as the Contributor.
    • Insert the shortcode: [woot id=1] (replacing 1 with the target ID).
    • Publish/Preview the post.
  6. Verify: Navigate to the public URL of the created post and check if the alert triggers.

6. Test Data Setup

  1. Plugin Setup: Install and activate profit-products-tables-for-woocommerce and woocommerce.
  2. User Creation:
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password
  3. Product Creation: (Optional, but helps rendering)
    • wp post create --post_type=product --post_title="Test Product" --post_status=publish
  4. Table Creation: Use the plugin UI or CLI to ensure at least one table structure exists in the database.

7. Expected Results

  • The AJAX request should return a success status (e.g., {"success":true}).
  • The wp_options or wp_postmeta table in the database should now contain the raw <script> payload.
  • Upon viewing the page containing the [woot] shortcode, the browser should execute the injected script, manifesting as an alert box or a failed network request (if using a blind XSS payload).

8. Verification Steps

  1. Database Check:
    wp option get woot_tables --format=json | grep "script"
    # OR if stored in meta:
    wp post meta list [TABLE_POST_ID] --keys=woot_table_settings
    
  2. Frontend Inspection:
    • Visit the post URL.
    • Search the HTML source for the payload:
      http_request GET [POST_URL] | grep -C 5 "alert(document.cookie)"
      

9. Alternative Approaches

  • CSS-Based XSS: If the title field is sanitized, try the css_classes field or custom_style fields if the "Constructor" allows them.
  • Shortcode Attribute Injection: If the AJAX save is too restrictive, check if the shortcode itself accepts attributes that are rendered without escaping:
    • [woot title='<script>alert(1)</script>']
  • Settings Export/Import: Check if the plugin has an Import/Export feature for table configurations. These often lack validation on the import side.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Active Products Tables for WooCommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting due to insufficient input sanitization and output escaping in its 'Constructor' feature. This allows authenticated attackers with Contributor-level access or higher to inject arbitrary JavaScript into table configurations, which then executes in the browsers of users viewing pages containing the table shortcode.

Security Fix

--- a/classes/constructor.php
+++ b/classes/constructor.php
@@ -45,7 +45,7 @@
     public function woot_save_table_settings() {
         check_ajax_referer('woot_save_table_settings', 'nonce');
         $table_id = intval($_POST['table_id']);
-        $settings = $_POST['settings'];
+        $settings = wp_kses_post($_POST['settings']);
         update_option("woot_settings_$table_id", $settings);
         wp_send_json_success();
     }
--- a/classes/woot.php
+++ b/classes/woot.php
@@ -120,5 +120,5 @@
     public function render_table($id) {
         $settings = get_option("woot_settings_$id");
         $data = json_decode($settings, true);
-        return "<h3>" . $data['title'] . "</h3>";
+        return "<h3>" . esc_html($data['title']) . "</h3>";
     }

Exploit Outline

1. Authenticate as a Contributor and access the WordPress admin dashboard to extract a valid AJAX nonce from the localized JavaScript variables (e.g., 'woot_vars.nonce'). 2. Send a POST request to '/wp-admin/admin-ajax.php' using the action 'woot_save_table_settings' and providing a JSON-encoded payload in the 'settings' parameter. 3. Within the JSON payload, inject a malicious script into a displayed field such as the table title or column names: {"title": "<script>alert(1)</script>", ...}. 4. Embed the shortcode for the modified table (e.g., [woot id=1]) into a new post or page and publish it. 5. The injected script will execute in the browser of any user, including administrators, who visits the page where the table is rendered.

Check if your site is affected.

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