WebToffee WooCommerce Product Feeds – Google Shopping, Pinterest, TikTok Ads, & More <= 2.3.3 - Authenticated (Shop manager+) PHP Object Injection
Description
The WebToffee WooCommerce Product Feeds – Google Shopping, Pinterest, TikTok Ads, & More plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 2.3.3 via deserialization of untrusted input. This makes it possible for authenticated attackers, with shop manager-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:H/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=2.3.3What Changed in the Fix
Changes introduced in v2.3.4
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-22480 - WebToffee WooCommerce Product Feeds PHP Object Injection ## 1. Vulnerability Summary The **WebToffee WooCommerce Product Feeds** plugin (up to version 2.3.3) is vulnerable to **PHP Object Injection** due to the insecure use of `maybe_unserialize()` on …
Show full research plan
Exploitation Research Plan: CVE-2026-22480 - WebToffee WooCommerce Product Feeds PHP Object Injection
1. Vulnerability Summary
The WebToffee WooCommerce Product Feeds plugin (up to version 2.3.3) is vulnerable to PHP Object Injection due to the insecure use of maybe_unserialize() on user-controlled data. Specifically, the export() method in the Webtoffee_Product_Feed_Sync_Export_Ajax class processes the form_data POST parameter without sufficient validation or prior sanitization, allowing an authenticated attacker (Shop Manager or higher) to inject arbitrary PHP objects into the application scope.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
wt_pf_export_ajax(inferred from plugin module structure and naming conventions) - Vulnerable Parameter:
form_data - Authentication Level: Authenticated (Shop Manager or Admin). Shop managers have the
manage_woocommercecapability, which is typically checked by this plugin viaWt_Pf_Sh::check_write_access(). - Preconditions: The attacker must obtain a valid WordPress nonce associated with the
webtoffee_product_feedaction.
3. Code Flow
- An AJAX request is sent to
admin-ajax.phpwith the actionwt_pf_export_ajax. - The plugin's AJAX dispatcher instantiates the class
Webtoffee_Product_Feed_Sync_Export_Ajax(located inadmin/modules/export/classes/class-export-ajax.php). - The dispatcher calls the
export()method (or routes via astepparameter likesteps[]=export). - Inside
admin/modules/export/classes/class-export-ajax.php, theexport()method is executed:public function export($out) { $offset=(isset($_POST['offset']) ? intval($_POST['offset']) : 0); // ... if( 0 == $offset ) /* first batch */ { /* process form data */ $form_data=(isset($_POST['form_data']) ? Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata(maybe_unserialize(wp_unslash($_POST['form_data']))) : array()); // ... } } wp_unslash($_POST['form_data'])retrieves the raw serialized string.maybe_unserialize()is called on this string, triggering the instantiation of any PHP objects defined in the payload if their classes are loaded.
4. Nonce Acquisition Strategy
The plugin uses a centralized security helper Wt_Pf_Sh::check_write_access(WEBTOFFEE_PRODUCT_FEED_ID) where WEBTOFFEE_PRODUCT_FEED_ID is 'webtoffee_product_feed'. The nonce is localized for the admin interface.
- Identify Page: The "Product Feed" export page is usually found at
wp-admin/admin.php?page=wt-product-feed&view=export. - Locate Nonce: The nonce is stored in a JavaScript object localized by the plugin, typically named
wt_pf_common_params. - Extraction:
- Navigate to the Export page:
browser_navigate("http://localhost:8080/wp-admin/admin.php?page=wt-product-feed&view=export"). - Extract the nonce:
browser_eval("window.wt_pf_common_params?.nonce"). - Alternatively, check for
wt_pf_export_params.nonce.
- Navigate to the Export page:
5. Exploitation Strategy
The exploit involves sending a crafted AJAX request containing a serialized PHP object in the form_data parameter.
- Request Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Parameters:
action:wt_pf_export_ajaxsteps[]:exportoffset:0_wpnonce:[EXTRACTED_NONCE]form_data:[SERIALIZED_PAYLOAD](e.g.,O:8:"stdClass":0:{}for testing)
Payload Construction:
Since the goal is to prove Object Injection, we can use a basic stdClass or, if searching for a POP chain, look for classes with __destruct or __wakeup methods in WordPress core or WooCommerce.
Summary
The plugin is vulnerable to PHP Object Injection via the `form_data` parameter used in product export and synchronization tasks. This occurs because the plugin uses `maybe_unserialize()` on user-controlled input without validation, allowing authenticated attackers with Shop Manager or higher privileges to inject arbitrary PHP objects.
Vulnerable Code
// admin/modules/export/classes/class-export-ajax.php public function export($out) { // ... (lines 191-196) if( 0 == $offset ) /* first batch */ { /* process form data */ $form_data=(isset($_POST['form_data']) ? Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata(maybe_unserialize(wp_unslash($_POST['form_data']))) : array()); //phpcs:ignore --- // admin/modules/cron/cron.php // ... (lines 1122) /* process form data */ $form_data=(isset($_POST['form_data']) ? Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata(maybe_unserialize(wp_unslash($_POST['form_data']))) : array()); //phpcs:ignore
Security Fix
@@ -1119,7 +1119,9 @@ } /* process form data */ - $form_data=(isset($_POST['form_data']) ? Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata(maybe_unserialize(wp_unslash($_POST['form_data']))) : array()); //phpcs:ignore + $form_data = isset( $_POST['form_data'] ) ? Webtoffee_Product_Feed_Sync_Common_Helper::wt_decode_data( $_POST['form_data'] ) : array(); //phpcs:ignore + /* process form data */ + $form_data = Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata($form_data); /* loading export module class object */ $this->module_obj=Webtoffee_Product_Feed_Sync::load_modules($action_type); @@ -1359,7 +1361,9 @@ $cron_form_details = maybe_unserialize($cron_details['data']); /* process form data */ - $form_data = (isset($_POST['form_data']) ? Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata(maybe_unserialize(wp_unslash($_POST['form_data']))) : array()); //phpcs:ignore + $form_data = isset( $_POST['form_data'] ) ? Webtoffee_Product_Feed_Sync_Common_Helper::wt_decode_data( $_POST['form_data'] ) : array(); //phpcs:ignore + /* process form data */ + $form_data = Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata($form_data); /* loading export module class object */ $this->module_obj = Webtoffee_Product_Feed_Sync::load_modules($action_type); @@ -193,7 +193,10 @@ if( 0 == $offset ) /* first batch */ { /* process form data */ - $form_data=(isset($_POST['form_data']) ? Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata(maybe_unserialize(wp_unslash($_POST['form_data']))) : array()); //phpcs:ignore + $form_data = isset( $_POST['form_data'] ) ? Webtoffee_Product_Feed_Sync_Common_Helper::wt_decode_data( $_POST['form_data'] ) : array(); //phpcs:ignore + /* process form data */ + $form_data = Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata($form_data); + //sanitize form data $form_data=Wt_Pf_IE_Basic_Helper::sanitize_formdata($form_data, $this->export_obj); @@ -300,8 +303,10 @@ $tb=$wpdb->prefix. Webtoffee_Product_Feed_Sync::$template_tb; + /* decode data */ + $form_data = isset( $_POST['form_data'] ) ? Webtoffee_Product_Feed_Sync_Common_Helper::wt_decode_data( $_POST['form_data'] ) : array(); //phpcs:ignore /* process form data */ - $form_data=(isset($_POST['form_data']) ? Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata(maybe_unserialize(wp_unslash($_POST['form_data']))) : array()); //phpcs:ignore + $form_data = Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata($form_data); //sanitize form data $form_data=Wt_Pf_IE_Basic_Helper::sanitize_formdata($form_data, $this->export_obj); @@ -666,7 +671,9 @@ $template_data=$this->get_mapping_template_by_id($id); if($template_data) { - $decoded_form_data=Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata(maybe_unserialize($template_data['data'])); + $decoded_form_data = isset( $template_data['data'] ) ? Webtoffee_Product_Feed_Sync_Common_Helper::wt_decode_data( $template_data['data'] ) : array(); //phpcs:ignore + /* process form data */ + $decoded_form_data = Webtoffee_Product_Feed_Sync_Common_Helper::process_formdata($decoded_form_data); $this->selected_template_form_data=(!is_array($decoded_form_data) ? array() : $decoded_form_data); } }
Exploit Outline
1. Gain authenticated access to a WordPress site with at least Shop Manager privileges. 2. Access the Product Feed export or configuration page to retrieve a valid WordPress nonce (usually named `webtoffee_product_feed`). 3. Construct a malicious serialized PHP object payload. 4. Send a POST request to `wp-admin/admin-ajax.php` with the action `wt_pf_export_ajax` and include the serialized payload in the `form_data` parameter. 5. If a suitable POP chain is present in the environment (e.g., in other plugins or themes), the object injection will trigger during the `maybe_unserialize` call, leading to arbitrary code execution or file deletion.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.