Critical WPBakery Stored Cross Site Scripting Risk//Published on 2025-10-15//CVE-2025-11160

WP-ফায়ারওয়াল সিকিউরিটি টিম

WPBakery Page Builder XSS Vulnerability

প্লাগইনের নাম WPBakery Page Builder
Type of Vulnerability Stored Cross Site Scripting
CVE Number CVE-2025-11160
জরুরি অবস্থা কম
CVE Publish Date 2025-10-15
Source URL CVE-2025-11160

WPBakery Page Builder <= 8.6.1 — Stored XSS via Custom JS Module (CVE-2025-11160): What site owners must do now

Intro

A stored Cross-Site Scripting (XSS) vulnerability affecting the WPBakery Page Builder plugin (versions <= 8.6.1) was disclosed with CVE-2025-11160. The issue allows an attacker with limited privileges to inject JavaScript into a site that is later executed in the context of visitors’ browsers. This is a real risk for websites that use the page builder and allow contributor-level or similar accounts to create or edit content.

As the team behind WP‑Firewall, we evaluate these kinds of vulnerabilities from two perspectives: (1) how the vulnerability works and who it affects, and (2) practical steps to protect your site immediately — via patching, configuration changes, detection, and WAF/virtual‑patching. This article breaks down the technical details, exploitation and impact scenarios, detection techniques, containment and remediation steps, and recommended web application firewall (WAF) rules and signatures you can apply right away.

Executive summary

  • Affected software: WPBakery Page Builder plugin (<= 8.6.1)
  • দুর্বলতা: Stored Cross‑Site Scripting (XSS) through the plugin’s custom JS module
  • CVE: CVE‑2025‑11160
  • এতে স্থির করা হয়েছে: 8.7 (upgrade immediately where possible)
  • Required privilege for exploitation (reported): Contributor (or equivalent low‑level editor)
  • Risk: Attackers able to create or edit page builder content can store JavaScript payloads that execute in site visitors’ browsers, enabling redirects, cookie theft, session hijacking, or distribution of malicious content.
  • Immediate mitigation: Update to 8.7+, restrict contributor access to page builder modules, search and clean site content, and enable WAF rules/virtual patching to block malicious script injection and execution.

How this vulnerability works (plain explanation)

Stored XSS occurs when an application happily stores untrusted input (for example, a JavaScript snippet submitted through a form) and later renders that content without proper output encoding or sanitization. When that stored content is delivered to another user’s browser, the script runs with the privileges of that site’s origin.

In this case, the plugin’s “Custom JS” module allowed JS content to be saved by contributors and later included in pages/templates that render on the front-end. Because the content could include raw JavaScript or DOM event attributes, visitors to an infected page would execute the attacker-provided code. The only privilege required is the ability to add or edit that custom module (reported as Contributor level), which is often granted to external writers, guest authors, or compromised accounts.

Why stored XSS is dangerous

Stored XSS is among the more severe XSS types because it doesn’t require the attacker to get a victim to click a crafted link; the malicious code is persistently stored and served to all visitors. Consequences can include:

  • Session cookie theft and account takeover (when cookies are not properly flagged)
  • Silent redirects to malicious domains
  • SEO spam and unauthorized content injection
  • Browser-based cryptocurrency miners or ad fraud
  • Secondary attacks: planting backdoors, malicious plugin/theme uploads (if admin account is compromised later)

Understanding the reported impact and severity

Public reporting lists CVE‑2025‑11160, fixed in version 8.7. The vulnerability was assigned a CVSS value around 6.5 in some assessments (the numeric score and classification may vary by assessor). Although a medium numeric severity may be shown, the real-world impact can climb quickly depending on:

  • The presence of high‑traffic pages using the custom JS module
  • Weak account hygiene (shared passwords, reuse, lack of MFA)
  • Whether visitors include privileged users (editors/admins) who could be targeted

Given how frequently contributor/author accounts are used for content management (guest posters, remote writers, marketing), this vulnerability deserves quick attention.

Immediate actions (step‑by‑step)

  1. Update WPBakery Page Builder to 8.7 or later
    • This is the definitive fix. Upgrade via WordPress admin or your deployment process as soon as possible.
    • If you cannot immediately upgrade (compatibility testing, large fleet deployments), apply the mitigations below.
  2. Restrict access to the “Custom JS” functionality
    • Temporarily revoke contributor/author access to the page builder module that allows custom JS.
    • If your site uses role managers (capability editors), remove capability for non‑trusted roles to edit page builder modules.
  3. Scan the site for malicious scripts and suspicious content
    • Search for script tags and common XSS patterns in posts, pages, postmeta, and page builder stored data.
    • Use the SQL queries and WP‑CLI commands below to find suspicious content.
  4. Enable WAF / virtual patching rules (see recommended rules further below)
    • Apply rules that block requests attempting to inject <script>, onerror=, javascript:, or encoded equivalents into post content or module settings.
    • Limit the rule scope to POST/PUT requests that create or update content and to users without administrator privileges when possible.
  5. Tighten account security
    • Enforce MFA for all administrative accounts.
    • Rotate passwords for users with content creation rights, especially if you suspect compromise.
    • Review user list for unknown or unused accounts and remove or suspend them.
  6. Monitor access logs and admin actions
    • Look for sudden POST requests to admin endpoints (/wp-admin/post.php, /wp-admin/admin-ajax.php) with suspicious payloads.
    • Check timestamps and IP addresses for unusual content edits.
  7. Incident response if infection is detected
    • Isolate or take the site offline temporarily if malicious payloads are found on high-traffic pages.
    • Clean or remove the malicious content from DB and files (use backups if necessary).
    • Re-scan for malicious files/backdoors.
    • Consider professional incident response for complex compromises.

Detecting stored XSS at the content level — practical checks

Search the WordPress database and postmeta table for script tags, javascript: URIs, or common event‑handler attributes:

  • Use WP‑CLI to search posts:
    wp db query "SELECT ID, post_title FROM wp_posts WHERE post_content LIKE '%<script%' OR post_content LIKE '%javascript:%' OR post_content LIKE '%onerror=%' LIMIT 100;"
  • Direct SQL (adjust table prefix as needed):
    SELECT ID, post_title, post_type FROM wp_posts WHERE post_content REGEXP '<(script|img|svg|iframe)[[:space:]>]' OR post_content REGEXP 'on(error|load|mouseover|click)=' LIMIT 500;
  • Scan postmeta (page builders often store module content in meta):
    SELECT meta_id, post_id, meta_key, meta_value FROM wp_postmeta WHERE meta_value LIKE '%<script%' OR meta_value LIKE '%javascript:%' OR meta_value LIKE '%onerror=%' LIMIT 500;
  • File system scan:
    grep -RIn --include="*.php" --include="*.js" --include="*.html" "<script" wp-content/ | head

Notes:

  • Page builder modules can store content in serialized arrays. Use tools to deserialize and inspect meta values.
  • False positives: some legitimate plugins or code snippets may include inline scripts (for analytics, widgets). Focus on unexpected scripts that weren’t placed by your team.

Practical cleanup checklist if you find malicious content

  • Identify and remove the specific module(s) or content entries containing malicious JS.
  • Replace any modified pages with clean content from backups if available.
  • If the content was used to inject redirectors or backdoors, scan files for recently modified files and unknown PHP files in wp-content.
  • Rotate API keys and credentials that may have been exposed.
  • Re-run malware scanner and verify removal.

WAF and virtual‑patching strategies (rules and examples)

When an official patch is available, update. While waiting, virtual patching via a WAF is an effective way to block exploitation attempts. Below are example detection strategies and sample rules (conceptual, for a ModSecurity‑style WAF). Tailor the rules to your environment to reduce false positives.

High level rule logic

  • Block POST/PUT requests that attempt to submit script-like content into content fields.
  • Target endpoints used for saving content (wp-admin/post.php, admin-ajax.php, REST API endpoints /wp-json/wp/v2/*).
  • Allow exceptions for administrator accounts (by IP or authenticated session) to avoid blocking legitimate admins while preventing low‑privilege users from injecting scripts.
  • Detect both plain and encoded payloads (URL-encoded, base64, unicode escape sequences).

Example: Block requests with raw <script> or onerror= in request body

SecRule REQUEST_METHOD "(POST|PUT)" "chain,phase:2,id:100001,log,deny,msg:'Block XSS attempt - script tag or event handler in POST body'"
SecRule REQUEST_HEADERS:Content-Type "!(multipart/form-data|application/x-www-form-urlencoded|application/json)" "t:none,chain"
SecRule REQUEST_BODY "(?:<|%3C)(?:s|S)(?:c|C)(?:r|R)(?:i|I)(?:p|P)(?:t|T)\b|on(?:error|load|mouseover|click)\s*=" "t:none,t:urlDecodeUni,t:lower,suspect,ctl:ruleRemoveById=100002"

Notes:

  • t:urlDecodeUni decodes Unicode and URL encoded payloads.
  • You may instead use distinct IDs and separate rules to detect event handlers or javascript: URIs.
  • You’ll need to tune to avoid blocking legitimate inline scripts used by administrators.

Example: block REST API calls that include script tags (restrict to non-admins)

SecRule REQUEST_URI "@beginsWith /wp-json/wp/v2/posts" "phase:2,chain,id:100010,log,deny,msg:'REST API XSS attempt'"
SecRule REQUEST_METHOD "POST" "chain"
SecRule &ARGS_NAMES "!@eq 0" "chain"
SecRule ARGS_NAMES|ARGS "(?:<(script)|on(error|load|click)|javascript:)" "t:urlDecodeUni,t:lower"

Notes:

  • The REST API is increasingly used to create/update content — inspect bodies for script-like payloads.
  • For sites using authenticated REST requests, make differentiations by user role when possible.

Example: Block submissions from unauthenticated or low privilege users

If your WAF can access session cookies or JWT claims, block requests that include script-like payloads when the session belongs to a non-admin role. This reduces false positives and allows admins to continue using legitimate inline scripts.

Generic defensive signature patterns

  • Detect “<script” (case-insensitive; URL encoded variants)
  • Detect “javascript:” URIs
  • Detect onerror=, onload=, onclick=, onmouseover=, etc.
  • Detect suspicious payload encodings like %3Cscript%3E or \u003cscript\u003e
  • Detect short obfuscated patterns common in XSS (e.g., document.cookie, eval(, Function(, window.location)

Content Security Policy (CSP) as defense-in-depth

A well-crafted CSP can significantly reduce the impact of stored XSS by preventing inline scripts and untrusted external script loads. Recommended CSP directives:

  • default-src ‘self’;
  • script-src ‘self’ ‘nonce-<random>’ https://trusted.cdn.example;
  • object-src ‘none’;
  • base-uri ‘self’;
  • form-action ‘self’;

Note:

  • Implement CSP carefully — inline scripts used by plugins may break. Use nonces or hashes for legit inline scripts.
  • CSP is not a silver bullet; it complements WAF and patching.

Hardening WordPress configuration to reduce exposure

  • Principle of least privilege: Only grant page‑builder editing capabilities to trusted users. Reassess contributor roles and capabilities.
  • Enforce strong passwords and two‑factor authentication for all users with content creation rights.
  • Disable or restrict theme/plugin editors from the WordPress admin (define(‘DISALLOW_FILE_EDIT’, true);).
  • Keep WordPress core, themes and all plugins updated. Use a staggered rollout in large fleets (test in staging).
  • Limit plugin/plugin admin UI access via IP allowlisting where possible.
  • Audit and remove unused plugins and themes.

Logging and monitoring guidance

  • Enable and retain server access logs and PHP error logs. Look for frequent POSTs to wp-admin/post.php coming from low privileged users.
  • Configure WAF alerts to send suspicious request data to your SIEM or logging endpoint with context (user agent, IP, authenticated username if available).
  • Track changes using content change monitoring or WordPress activity logs to identify when malicious modules were added and by which account.
  • Integrate scans with a regular automated security scanning routine to detect new indicators.

Forensics: what to look for after an attack

  • New or recently modified posts or pages with inline <script> tags
  • New admin or editor accounts created without approval
  • Unexpected outbound connections from the site (e.g., DNS to suspicious domains, POSTs to unknown endpoints)
  • Modified core files or plugin/theme files with obfuscated code
  • New scheduled tasks (cron jobs) that could trigger payload persistence

Testing and verification

  • Test upgrades and WAF rules on a staging copy. Never apply untested rules in production that could block legitimate editor workflows.
  • After cleaning, re-scan site and re-check search results from the SQL and WP‑CLI queries provided earlier.
  • Validate that pages render correctly in major browsers after CSP and WAF changes.

Developer guidance (for plugin/theme teams)

  • Never store unescaped user input that can be executed. Always sanitize input on entry and escape output on render.
  • Use WordPress functions:
    • sanitize_text_field(), wp_kses_post(), wp_kses() to strip or whitelist HTML
    • esc_js(), esc_html(), esc_attr() on output depending on context
  • For fields intended to accept code, restrict who can edit them and store them in a safe way (for example, require admin approval or store only after sanitization/whitelisting).
  • Consider using shortcodes with sanitized attributes instead of saving full raw JS blocks in content.

How WP‑Firewall protects you (virtual patching and continuous protection)

At WP‑Firewall we recommend a layered approach:

  • Immediate patching to the fixed plugin version (8.7+)
  • For environments where immediate patching is not possible, enable virtual patching rules that:
    • Intercept content‑save requests and block script or event handler payloads
    • Limit the ability to save content with script‑like payloads to administrators or approved IP ranges
    • Provide detailed forensic logs to quickly locate and identify the impacted pages and the accounts that made edits
  • Continuous monitoring to detect re-injection attempts and to block automated exploitation.

New: Free plan to start protecting your site

Protect Your Site — Start with WP‑Firewall’s Free Plan

If you want to add immediate managed protection while you patch, sign up for our free plan. The free plan provides essential protection: a managed firewall, an always‑on WAF, unlimited bandwidth protection, a malware scanner, and mitigation of OWASP Top‑10 risks so you can block attempts to exploit this and other vulnerabilities while you remediate.

Sign up and get started here: https://my.wp-firewall.com/buy/wp-firewall-free-plan/

(If you need more automation—automatic malware removal, per‑site blacklisting/whitelisting, monthly security reports, or auto virtual‑patching—see the upgrade options in the dashboard. But the free tier is a good, fast first step to block exploit traffic while you remediate.)

Operational timelines and priorities

  • Immediate (0–24 hours):
    • Upgrade plugin to 8.7 if possible.
    • If not, restrict access to page builder custom JS modules and enable WAF rules blocking script-like POST content.
    • Search for and remove any stored scripts.
  • Short term (1–7 days):
    • Harden accounts, enable MFA, rotate credentials for any accounts with suspicious activity.
    • Monitor logs and user activity.
  • Mid term (1–4 weeks):
    • Validate that all instances in your fleet are updated.
    • Conduct full site scans for backdoors and unauthorized admin accounts.
    • Review plugin usage policies and limit who can add rich content or custom JS.
  • Long term (ongoing):
    • Maintain an automated vulnerability management process, patching cadence, and security monitoring.
    • Ensure WAF rules are maintained and tuned based on observed traffic and false positives.

FAQ — quick answers

Q: Can this XSS be exploited by anonymous site visitors?
A: No. The vulnerability requires the ability to submit a custom JS module (reported as Contributor privilege), so the attacker needs an account with content-edit capabilities or to have compromised such an account.

Q: Is removing the plugin safer than updating?
A: If you can remove the plugin without breaking the site, that removes the attack surface. However, many sites rely on the page builder for layout and content. The recommended action is to update to the fixed version (8.7+) and apply the access controls and WAF rules described here. If you remove the plugin, verify that no residual content still contains inline scripts.

Q: Will a WAF catch everything?
A: No single measure catches everything. WAFs are very effective at reducing exploitation attempts, especially when combined with prompt patching, account hardening, and content scanning. Use virtual patching as a stop‑gap while you perform the full remediation.

Concluding recommendations — what to do right now

  1. Update WPBakery Page Builder to 8.7 or later immediately.
  2. If you can’t update right now, restrict contributor roles from accessing the custom JS module and enable WAF rules to block script injection attempts.
  3. Search and clean site content for stored scripts using the SQL/WP‑CLI queries above.
  4. Enforce MFA and perform a credentials rotation for content editors if you suspect suspicious edits.
  5. Consider enabling a managed WAF (like the free protection plan above) to virtual‑patch and block exploit attempts while you remediate.
  6. Review site monitoring and logging; ensure alerts are configured for suspicious POSTs to admin endpoints.

Appendix — handy commands and rule examples

SQL to find scripts in posts:
SELECT ID, post_title FROM wp_posts WHERE post_content REGEXP '(?i)<script|javascript:|on(error|load|click)=' LIMIT 500;

Sample ModSecurity snippet (conceptual):

SecRule REQUEST_METHOD "(POST|PUT)" "phase:2,deny,id:100200,msg:'XSS payload detected in request body',log,t:none"
SecRule REQUEST_BODY "@rx (?i)(?:<\s*script\b|on(?:error|load|click)\s*=|javascript:|document\.cookie|eval\()" "t:urlDecodeUni,t:lower"

WP‑CLI example to dump suspicious postmeta:
wp db query "SELECT post_id, meta_key FROM wp_postmeta WHERE meta_value LIKE '%<script%' OR meta_value LIKE '%onerror=%' LIMIT 200;"

Final note from the WP‑Firewall security team

Stored XSS vulnerabilities are particularly insidious because they persist until found and cleaned. If you use page builders and provide editing permissions to non‑trusted users, double down on access control and monitoring. Update to the fixed plugin version, clean any injected scripts, and enable virtual patching/WAF protections to reduce the window of exposure. If you’d like immediate protection while you patch, start with our free managed firewall plan to stop exploit attempts in their tracks: https://my.wp-firewall.com/buy/wp-firewall-free-plan/

— WP‑Firewall security team


wordpress security update banner

বিনামূল্যে WP নিরাপত্তা সাপ্তাহিক পান 👋
এখন সাইন আপ করুন
!!

প্রতি সপ্তাহে আপনার ইনবক্সে ওয়ার্ডপ্রেস সিকিউরিটি আপডেট পেতে সাইন আপ করুন।

আমরা স্প্যাম করি না! আমাদের পড়ুন গোপনীয়তা নীতি আরও তথ্যের জন্য।