CVE-2026-48971

Product Import Export for WooCommerce – Import Export Product CSV Suite <= 2.5.6 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.5.7
Patched in
6d
Time to patch

Description

The Product Import Export for WooCommerce – Import Export Product CSV Suite plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.5.6. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.5.6
PublishedMay 27, 2026
Last updatedJune 1, 2026

What Changed in the Fix

Changes introduced in v2.5.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-48971 - Missing Authorization ## 1. Vulnerability Summary The **Product Import Export for WooCommerce** plugin (<= 2.5.6) contains a missing authorization vulnerability in its banner dismissal logic. Specifically, the AJAX handler `wt_p_iew_dismiss_cta_banner_…

Show full research plan

Exploitation Research Plan: CVE-2026-48971 - Missing Authorization

1. Vulnerability Summary

The Product Import Export for WooCommerce plugin (<= 2.5.6) contains a missing authorization vulnerability in its banner dismissal logic. Specifically, the AJAX handler wt_p_iew_dismiss_cta_banner_default_page (and potentially others like those related to BFCM banners) fails to perform a capability check (e.g., current_user_can( 'manage_woocommerce' )). This allows any authenticated user, including those with Subscriber privileges, to modify plugin options (specifically the dismissal state of admin notices) via the admin-ajax.php endpoint.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: wt_p_iew_dismiss_cta_banner_default_page (Registered in admin/banner/class-wt-p-iew-cta-banner-default-page.php)
  • HTTP Method: POST
  • Required Parameters:
    • action: wt_p_iew_dismiss_cta_banner_default_page
    • _wpnonce: (Possibly required, depending on the implementation of dismiss_product_cta_banner)
  • Authentication: Authenticated, Subscriber-level or higher.
  • Preconditions: None, as long as the user can log in and access the WordPress dashboard (e.g., wp-admin/profile.php).

3. Code Flow

  1. Entry Point: The plugin registers the AJAX hook in the constructor of WT_P_IEW_CTA_Banner_Default_Page:
    // admin/banner/class-wt-p-iew-cta-banner-default-page.php
    add_action('wp_ajax_wt_p_iew_dismiss_cta_banner_default_page', array($this, 'dismiss_product_cta_banner'));
    
  2. AJAX Call: A Subscriber sends a POST request to admin-ajax.php with the action wt_p_iew_dismiss_cta_banner_default_page.
  3. Execution: The WordPress AJAX dispatcher calls $this->dismiss_product_cta_banner().
  4. Vulnerable Sink: The function (inferred based on usage in product_cta_banner_in_default_page) likely executes:
    public function dismiss_product_cta_banner() {
        // MISSING: current_user_can() check
        update_option( 'wt_p_iew_product_cta_banner_default_page_dismissed', 1 );
        wp_send_json_success();
    }
    
    The logic flaw is that any logged-in user can trigger this update_option call because the wp_ajax_ hook is available to all authenticated users.

4. Nonce Acquisition Strategy

While the provided snippet is truncated, the JS file admin/banner/assets/js/wtier-bfcm-twenty-twenty-four.js shows a pattern for nonces:
_wpnonce: wtier_bfcm_twenty_twenty_four_banner_js_params.nonce

If wt_p_iew_dismiss_cta_banner_default_page requires a nonce, it is likely localized via wp_localize_script. Since a Subscriber can access wp-admin/profile.php, we can check if the plugin enqueues its parameters there.

Steps:

  1. Log in as a Subscriber.
  2. Navigate to /wp-admin/profile.php.
  3. Use browser_eval to search for localized objects. Possible candidates based on the code:
    • window.wtier_bfcm_twenty_twenty_four_banner_js_params
    • window.wt_p_iew_params (Inferred common pattern)
    • window.wt_p_iew_banner_params (Inferred)
  4. If a nonce is found, use it in the POST request. If no nonce check is implemented in the PHP handler, the request will work without it.

5. Exploitation Strategy

We will attempt to trigger the dismissal of the "Default Page Banner" by updating the wt_p_iew_product_cta_banner_default_page_dismissed option.

Step 1: Discover the Nonce (if applicable)

Navigate to the admin dashboard as a Subscriber and extract any potential nonces.

// Example JS to run via browser_eval
JSON.stringify(window.wtier_bfcm_twenty_twenty_four_banner_js_params || window.wt_p_iew_params || "No nonce object found")

Step 2: Trigger the Unauthorized Action

Send the AJAX request using the http_request tool.

Request:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=wt_p_iew_dismiss_cta_banner_default_page&_wpnonce=[NONCE_IF_FOUND]
    

6. Test Data Setup

  1. Target User: Create a user with the subscriber role.
  2. Plugin State: Ensure the plugin is active.
  3. Verify Initial State:
    • Run wp option get wt_p_iew_product_cta_banner_default_page_dismissed.
    • It should return false or "Could not find" (meaning the banner is NOT dismissed).

7. Expected Results

  • The server should respond with a 200 OK and likely a JSON success message: {"success":true}.
  • The option wt_p_iew_product_cta_banner_default_page_dismissed should be created/updated in the database.

8. Verification Steps

After performing the HTTP request, use WP-CLI to confirm the option was changed:

wp option get wt_p_iew_product_cta_banner_default_page_dismissed

Success Criteria: The command returns 1 or true.

9. Alternative Approaches

If wt_p_iew_dismiss_cta_banner_default_page is protected, investigate the BFCM (Black Friday) banner dismissal, which uses the following identifiers from the provided JS/CSS:

  • JS Action Param: wtier_bfcm_twenty_twenty_four_banner_js_params.action
  • Likely AJAX Action: wtier_bfcm_twenty_twenty_four_banner_action (inferred from variable names)
  • Likely Option: wtier_bfcm_twenty_twenty_four_banner_dismissed (inferred)

Use the same logic: find the localized object wtier_bfcm_twenty_twenty_four_banner_js_params and trigger its action as a Subscriber.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Product Import Export for WooCommerce plugin is vulnerable to unauthorized modification of plugin settings due to a missing capability check in its AJAX handlers for admin notice dismissal. Authenticated attackers with subscriber-level permissions or higher can trigger the dismissal of promotional banners across the site by invoking the 'wt_p_iew_dismiss_cta_banner_default_page' AJAX action.

Vulnerable Code

// admin/banner/class-wt-p-iew-cta-banner-default-page.php
public function __construct()
{
    add_action('admin_footer', array($this, 'product_cta_banner_in_default_page'));
    // Vulnerable AJAX hook registered for all authenticated users without capability check
    add_action('wp_ajax_wt_p_iew_dismiss_cta_banner_default_page', array($this, 'dismiss_product_cta_banner'));
}

// Line numbers inferred based on constructor position (~190-200)
public function dismiss_product_cta_banner() {
    // MISSING: current_user_can('manage_woocommerce') check
    update_option( 'wt_p_iew_product_cta_banner_default_page_dismissed', 1 );
    wp_send_json_success();
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/product-import-export-for-woo/2.5.6/admin/banner/class-wt-p-iew-cta-banner-default-page.php /home/deploy/wp-safety.org/data/plugin-versions/product-import-export-for-woo/2.5.7/admin/banner/class-wt-p-iew-cta-banner-default-page.php
--- /home/deploy/wp-safety.org/data/plugin-versions/product-import-export-for-woo/2.5.6/admin/banner/class-wt-p-iew-cta-banner-default-page.php	2025-09-02 17:31:06.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/product-import-export-for-woo/2.5.7/admin/banner/class-wt-p-iew-cta-banner-default-page.php	2025-10-30 10:52:08.000000000 +0000
@@ -154,7 +154,7 @@
                             type: 'POST',
                             data: {
                                 action: 'wt_p_iew_dismiss_cta_banner_default_page',
-                                nonce: '<?php echo wp_create_nonce( 'wt_p_iew_dismiss_cta_banner_default_page' ); ?>'
+                                nonce: '<?php echo esc_js(wp_create_nonce( 'wt_p_iew_dismiss_cta_banner_default_page' )); ?>'
                             },
                             dataType: 'json',
                             success: function(response) {
@@ -194,6 +194,10 @@
 		 */
 		public function dismiss_product_cta_banner() {
 			check_ajax_referer( 'wt_p_iew_dismiss_cta_banner_default_page', 'nonce' );
+
+			if ( ! current_user_can( 'manage_woocommerce' ) ) {
+				wp_send_json_error( array( 'message' => __( 'You do not have permission to perform this action.', 'product-import-export-for-woo' ) ) );
+			}
+
 			update_option( 'wt_p_iew_product_cta_banner_default_page_dismissed', 1 );
 			wp_send_json_success();
 		}

Exploit Outline

1. Authentication: Log in as a user with at least Subscriber-level privileges. 2. Nonce Acquisition: Access any admin page (like /wp-admin/profile.php) and inspect the localized JavaScript objects (e.g., in the source of the banner rendering logic) to find the 'wt_p_iew_dismiss_cta_banner_default_page' nonce. 3. Payload Construction: Prepare an AJAX POST request to '/wp-admin/admin-ajax.php'. 4. Request Parameters: Set 'action' to 'wt_p_iew_dismiss_cta_banner_default_page' and '_wpnonce' to the extracted nonce value. 5. Execution: Dispatch the POST request. The server will execute 'dismiss_product_cta_banner', which updates the 'wt_p_iew_product_cta_banner_default_page_dismissed' option to '1', effectively altering site-wide plugin configurations without the necessary administrative permissions.

Check if your site is affected.

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