| Plugin Name | WPBakery Page Builder |
|---|---|
| Type of Vulnerability | Stored Cross-Site Scripting |
| CVE Number | CVE-2025-11160 |
| Urgency | Low |
| CVE Publish Date | 2025-10-15 |
| Source URL | CVE-2025-11160 |
WPBakery Page Builder <= 8.6.1 — Stored XSS in Custom JS Module (CVE-2025-11160)
Summary: A stored Cross-Site Scripting (XSS) issue affects WPBakery Page Builder versions up to and including 8.6.1. The vector is the plugin’s Custom JS module and the flaw can be exploited by an authenticated user with Contributor-level privileges. The vendor released a fix in version 8.7. This write-up — written with a Hong Kong security professional’s focus on clarity and practicality — explains how the issue works, who is at risk, how to detect and remove payloads, and what immediate mitigations to apply.
- Vulnerability: Stored XSS in WPBakery Custom JS module
- Affected versions: WPBakery <= 8.6.1
- Fixed in: WPBakery 8.7
- CVE: CVE-2025-11160
- Required privilege: Contributor (authenticated)
- Reported CVSS: 6.5 (context-dependent)
- Primary impact: Persistent JavaScript execution in visitors’ and potentially admins’ browsers (cookie theft, redirects, persistent defacement, pivoting)
What is Stored XSS and why it matters for WordPress
Stored XSS occurs when an attacker stores malicious JavaScript on the site (in posts, postmeta, widgets, or plugin-managed fields) and the site later serves that content without proper output encoding. The payload executes whenever anyone (including administrators) views the affected page.
Why WordPress sites are high-value targets:
- Admin-facing pages and previews can execute the payload, enabling credential theft or session capture.
- Persistent scripts can add backdoors, inject SEO spam, or perform redirects and content manipulation.
- Sites with user registration or contributor workflows are especially vulnerable because a low-privilege account is sufficient to store payloads.
In this case the plugin exposes a Custom JS module intended for legitimate front-end scripts; inadequate input constraints and sanitisation allow a contributor to persist a malicious script that will be executed in visitors’ browsers.
Technical overview: how this WPBakery vulnerability works
- The Custom JS module stores content in the database (shortcode, postmeta or plugin-specific storage).
- Input from contributor-level users is not properly constrained or sanitised before being saved and later rendered.
- A malicious contributor can inject JavaScript that is stored and later returned to any visitor who views the page.
Likely attack scenarios:
- Steal admin cookies or session tokens when an administrator previews or visits an infected page and then exfiltrate them to an external server.
- Perform persistent redirects to attacker domains, load external malware, or insert spam links.
- Use DOM manipulation to capture form submissions or escalate to additional actions via the REST API or AJAX calls.
Note: The exploit requires at least a Contributor account. Many sites allow registrations or have weak verification — that is the usual path for attackers.
Who is at risk?
- Sites running WPBakery Page Builder ≤ 8.6.1.
- Sites permitting user registration or accepting content from untrusted contributors.
- Multi-author blogs and community or membership sites that allow contributor roles.
- Any site where admins preview pages while logged in (a common practice).
Even with a moderate CVSS, a single exposed contributor-enabled site can lead to a serious compromise if an admin is targeted.
Immediate actions (first 1–2 hours)
-
Confirm plugin version
Dashboard: Plugins > Installed Plugins and verify WPBakery version.
WP-CLI:
wp plugin list --format=csv | grep js_composer || wp plugin get js_composer --field=version -
Update to 8.7+ if you can
If allowed by your license and compatibility matrix, update via Dashboard or WP-CLI:
wp plugin update js_composer --clear-plugins-cacheIf you cannot update immediately, apply virtual patching (see WAF advice below) while you schedule the update.
-
Limit contributor access temporarily
Remove or restrict the Contributor role until you can update and scan. Remove the capability to add custom JS modules for low-privilege roles.
- Scan for injected
- Inline event handlers:
onerror=,onclick=,onload= - APIs and functions used in theft/exfiltration:
document.cookie,XMLHttpRequest,fetch,new Image() - Obfuscation:
base64,eval(atob(...)), long encoded strings - Backup and snapshot: Preserve the current DB and file system for analysis.
- Remove or neutralise malicious entries:
- For script tags in post content, remove offending //g')"
- Rotate credentials: Reset passwords for any accounts that may have been used to inject content.
- Force password resets: Require all admins and editors to reset passwords if suspicious activity is present.
- Manual inspection of plugins/themes: Review any plugin or theme that permits storing JavaScript; prioritise manual code review for such components.
- Harden registrations and roles:
- Disable open registration if not required.
- Convert unverified contributor accounts to safer roles or suspend them.
- Use approval-based workflows for user-generated content.
- Review server logs: Look for POST requests to admin-ajax.php, REST API endpoints, or other content endpoints near the time malicious content appeared.
- Restore if needed: If the infection breadth is unclear, restore from a known-clean backup, update to the fixed plugin version, and reintroduce content after scanning.
Database search examples (escape special characters carefully):
SELECT ID, post_title
FROM wp_posts
WHERE post_content REGEXP '
SELECT post_id, meta_key
FROM wp_postmeta
WHERE meta_value REGEXP '
WP-CLI / file scanning examples:
wp db export - | grep -iE '
grep -R --line-number -E "
If you find matches, document each affected post ID and meta key, export snapshots, and keep forensic copies before modifying content.
Containment & cleanup (detailed steps)
Short-term mitigation with a managed WAF (virtual patching)
If updating immediately is not possible, virtual patching via a web application firewall (WAF) can reduce exposure. The purpose is to block exploit attempts and known payload patterns until you can update and clean the site.
Conceptual WAF rule examples (implement via your WAF or gateway):