CVE-2026-22354

Woocommerce Category Banner Management <= 2.5.1 - Authenticated (Contributor+) PHP Object Injection

highDeserialization of Untrusted Data
7.5
CVSS Score
7.5
CVSS Score
high
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Woocommerce Category Banner Management plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 2.5.1 via deserialization of untrusted input. This makes it possible for authenticated attackers, with contributor-level access and above, to inject a PHP Object. No known POP chain is present in the vulnerable software. If a POP chain is present via an additional plugin or theme installed on the target system, it could allow the attacker to delete arbitrary files, retrieve sensitive data, or execute code.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.5.1
PublishedFebruary 16, 2026
Last updatedFebruary 25, 2026
Research Plan
Unverified

This research plan focuses on identifying and exploiting a PHP Object Injection vulnerability in the **Banner Management, Product Slider, Product Carousel for WooCommerce** plugin (version <= 2.5.1). --- ### 1. Vulnerability Summary The vulnerability is a PHP Object Injection (POI) residing in the…

Show full research plan

This research plan focuses on identifying and exploiting a PHP Object Injection vulnerability in the Banner Management, Product Slider, Product Carousel for WooCommerce plugin (version <= 2.5.1).


1. Vulnerability Summary

The vulnerability is a PHP Object Injection (POI) residing in the administrative backend of the plugin. It occurs when user-supplied data from a POST parameter is passed directly into the PHP unserialize() function without prior validation or sanitization. While the plugin itself may not contain a usable POP chain, an attacker can leverage POP chains present in WordPress core (e.g., Requests_Utility_FilteredIterator in older versions) or other installed plugins to achieve Remote Code Execution (RCE) or file manipulation.

The vulnerability is accessible to users with Contributor roles or higher, which is atypical for WooCommerce management plugins and suggests a lack of proper capability checks on the vulnerable AJAX or admin action.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php (Inferred) or a specific admin page submission handler.
  • Action: Likely a wp_ajax_ action such as wccbm_save_settings, wccbm_update_banner, or save_slider_data (Inferred).
  • Vulnerable Parameter: A POST parameter often named data, settings, config, or wccbm_options (Inferred).
  • Authentication: Authenticated, Contributor-level access (PR:L).
  • Preconditions: The attacker must have a valid login for a user with the contributor role.

3. Code Flow (Trace)

  1. Entry Point: The plugin registers an AJAX handler for authenticated users:
    add_action('wp_ajax_wccbm_save_category_banner', array($this, 'wccbm_save_category_banner_callback')); (Inferred identifiers).
  2. Capability Check: The callback function likely lacks a strict current_user_can('manage_options') check, instead using a weaker check or no check at all, allowing Contributors to trigger it.
  3. Nonce Verification: The handler likely calls check_ajax_referer('wccbm_nonce_action', 'security').
  4. Data Retrieval: The code fetches a POST parameter containing serialized data:
    $banner_data = $_POST['banner_data'];
  5. Sink: The raw input is passed to the vulnerable sink:
    $decoded_data = unserialize(stripslashes($banner_data)); (Inferred).

4. Nonce Acquisition Strategy

To exploit the AJAX endpoint, a valid nonce is required.

  1. Identify Localization: The plugin likely localizes a nonce for its administrative scripts. Look for wp_localize_script calls in the plugin source (e.g., in admin/class-banner-management-for-woocommerce-admin.php).
  2. Trigger Page: Navigate to the plugin's settings page or a category edit page where the banner management UI appears.
  3. Extraction:
    • Post Creation: If the settings are only visible on certain pages, create a post: wp post create --post_type=post --post_status=publish --post_title="Exploit" --post_author=[CONTRIBUTOR_ID]
    • Browser Navigate: Navigate to the WordPress dashboard as the Contributor user.
    • Browser Eval: Use the following JS to extract the nonce:
      browser_eval("window.wccbm_admin_obj?.nonce || window.wccbm_params?.ajax_nonce") (Inferred JS keys; verify with grep -r "wp_localize_script" . first).

5. Exploitation Strategy

The goal is to trigger the unserialize() call with a crafted object.

Step 1: Identify the exact AJAX action and parameter
Run the following inside the plugin directory:

grep -rn "unserialize" .
grep -rn "wp_ajax" .

Verify which wp_ajax handler leads to an unserialize call.

Step 2: Construct the Payload
Since we are demonstrating POI, we will use a "pingback" or "logger" object if available, or a standard WordPress core POP chain to trigger a noticeable effect (like an error or a file modification).
For a simple PoC, an invalid object that triggers __wakeup can be used to confirm the injection:
O:8:"NonExistentClass":0:{}

Step 3: Execute the Attack
Send a POST request to admin-ajax.php.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
    • Cookie: [Contributor Session Cookies]
  • Body:
    action=[ACTION_NAME]&security=[NONCE]&[VULNERABLE_PARAM]=O:8:"NonExistentClass":0:{}

6. Test Data Setup

  1. User Creation:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
  2. Plugin Activation:
    wp plugin activate banner-management-for-woocommerce
  3. Identify Localization Key:
    Use grep -r "wp_localize_script" . to find the JavaScript object name used to store the nonce.

7. Expected Results

  • Successful Injection: The server response should indicate the action was processed (even if it returns a 500 error due to the NonExistentClass or successful execution of a chain).
  • Verification of Deserialization: If a POP chain is used (e.g., Requests_Utility_FilteredIterator), the server may attempt to execute the callback function defined in the serialized object, which can be verified via logs or side-effects.

8. Verification Steps

  1. Check PHP Error Logs: Look for "PHP Fatal error: unserialize(): Expected to be a closure" or "Class NonExistentClass not found" errors, which confirm the unserialize() function was reached with our input.
    tail -n 20 /var/www/html/wp-content/debug.log
  2. Function Call Verification: If utilizing a POP chain to call phpinfo() or system(), check the HTTP response body for the output of those commands.

9. Alternative Approaches

  • Settings Save Hook: If the POI is not in an AJAX handler, check the admin_init or admin_post hooks. Some plugins process settings during the admin_init hook by checking $_POST directly.
  • Category Meta: Check if the vulnerability exists when editing a WooCommerce category. The plugin adds banner fields to the edit-tags.php page. Deserialization might occur when saving these custom fields.
    • Action: edited_product_cat
    • Payload Location: The field used for banner configuration data.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WooCommerce Category Banner Management plugin is vulnerable to PHP Object Injection via the unserialize() function when processing user-supplied data in administrative AJAX actions. Authenticated attackers with Contributor-level access can exploit this by submitting crafted serialized payloads, potentially leading to remote code execution or file manipulation if a suitable POP chain is present on the system.

Vulnerable Code

// Inferred from plugin functionality and research plan
// File: admin/class-banner-management-for-woocommerce-admin.php

add_action('wp_ajax_wccbm_save_category_banner', array($this, 'wccbm_save_category_banner_callback'));

public function wccbm_save_category_banner_callback() {
    // Nonce verification often present but insufficient for authorization
    check_ajax_referer('wccbm_nonce_action', 'security');

    if (isset($_POST['banner_data'])) {
        $banner_data = $_POST['banner_data'];
        // Vulnerable sink: Raw POST data is passed to unserialize
        $decoded_data = unserialize(stripslashes($banner_data));
        
        // ... logic to save settings
    }
}

Security Fix

--- a/admin/class-banner-management-for-woocommerce-admin.php
+++ b/admin/class-banner-management-for-woocommerce-admin.php
@@ -10,7 +10,13 @@
 public function wccbm_save_category_banner_callback() {
-    $decoded_data = unserialize(stripslashes($_POST['banner_data']));
+    if ( ! current_user_can( 'manage_woocommerce' ) ) {
+        wp_die( -1 );
+    }
+
+    $decoded_data = json_decode(stripslashes($_POST['banner_data']), true);
+    if ( json_last_error() !== JSON_ERROR_NONE ) {
+        // Handle error
+    }

Exploit Outline

1. Authenticate as a user with at least Contributor-level privileges. 2. Access the WordPress dashboard to extract a valid AJAX nonce from localized scripts (e.g., the 'wccbm_params' or 'wccbm_admin_obj' global variables). 3. Identify the vulnerable AJAX action (e.g., 'wccbm_save_category_banner') and the parameter being deserialized (e.g., 'banner_data'). 4. Generate a PHP serialized object payload utilizing a known POP chain available in the environment (such as those found in WordPress core like Requests_Utility_FilteredIterator or other installed plugins). 5. Send a POST request to /wp-admin/admin-ajax.php containing the action, the security nonce, and the malicious serialized object in the vulnerable parameter. 6. Observe side effects or check logs to verify the execution of the injected object's magic methods (__wakeup, __destruct, etc.).

Check if your site is affected.

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