Business Template Blocks for WPBakery (Visual Composer) Page Builder <= 1.3.2 - Reflected Cross-Site Scripting
Description
The Business Template Blocks for WPBakery (Visual Composer) Page Builder plugin for WordPress is vulnerable to Reflected Cross-Site Scripting in versions up to, and including, 1.3.2 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NTechnical Details
<=1.3.2This plan outlines the research and exploitation strategy for **CVE-2025-69390**, a reflected cross-site scripting vulnerability in the "Business Template Blocks for WPBakery" plugin. --- ### 1. Vulnerability Summary The "Business Template Blocks for WPBakery" plugin fails to properly sanitize or …
Show full research plan
This plan outlines the research and exploitation strategy for CVE-2025-69390, a reflected cross-site scripting vulnerability in the "Business Template Blocks for WPBakery" plugin.
1. Vulnerability Summary
The "Business Template Blocks for WPBakery" plugin fails to properly sanitize or escape user-controlled input before reflecting it back in the browser. This occurs in one or more code paths accessible to unauthenticated users, likely within an AJAX handler or a frontend initialization hook. The vulnerability allows an attacker to execute arbitrary JavaScript in the context of the victim's session.
2. Attack Vector Analysis
- Endpoint: Likely
wp-admin/admin-ajax.php(viawp_ajax_nopriv_actions) or a frontend page (viainitorwp_loadedhooks). - Parameter: A GET or POST parameter (likely
id,template,style, orclass). - Authentication: Unauthenticated (PR:N).
- Preconditions: The plugin must be active. If the vulnerability is in an AJAX handler, a nonce might be required.
3. Code Flow (Inferred)
- Entry Point: An unauthenticated user sends an HTTP request with a malicious payload in a query parameter.
- Hook Registration: The plugin registers a handler via
add_action('wp_ajax_nopriv_[ACTION_NAME]', ...)oradd_action('init', ...). - Vulnerable Handler: The handler retrieves the parameter from
$_GET,$_POST, or$_REQUEST. - Sink: The handler echoes the parameter directly using
echo,print, orprintfwithout applyingesc_html(),esc_attr(), orwp_kses(). - Output: The response contains the unescaped script, which executes in the browser.
4. Nonce Acquisition Strategy
If the vulnerability resides in an AJAX handler that enforces a nonce check (e.g., check_ajax_referer or wp_verify_nonce), follow these steps:
- Identify Action and Script: Search the plugin code for
wp_localize_scriptto find the JavaScript object name and nonce key.- Search Command:
grep -r "wp_localize_script" /var/www/html/wp-content/plugins/templates-and-addons-for-wpbakery-page-builder/
- Search Command:
- Locate Trigger Shortcode: Determine if the script is only loaded when a specific shortcode is present.
- Search Command:
grep -r "add_shortcode" /var/www/html/wp-content/plugins/templates-and-addons-for-wpbakery-page-builder/
- Search Command:
- Create Dummy Page: If a shortcode is required, create a page:
wp post create --post_type=page --post_status=publish --post_title="Exploit Page" --post_content='[SHORTCODE_NAME]'
- Extract Nonce:
- Navigate to the page using
browser_navigate. - Execute
browser_eval("window.LOCALIZED_OBJECT?.nonce_key")to retrieve the valid nonce.
- Navigate to the page using
- Note: If the plugin calls
check_ajax_refererwithdie=falseand fails to check the return value, the nonce can be omitted or be invalid.
5. Exploitation Strategy
The goal is to find the specific parameter that reflects input.
- Discovery Phase:
- Search for all
wp_ajax_nopriv_actions:grep -r "wp_ajax_nopriv_" . - Search for
echostatements involving superglobals:grep -rP "echo\s+\\\$_(GET|POST|REQUEST)" .
- Search for all
- Candidate Actions (Inferred):
btb_load_templatebtb_previewget_template_blocks
- Payload Construction:
- Primary:
<script>alert(document.domain)</script> - Attribute Breakout (if reflected in an attribute):
"><script>alert(1)</script>
- Primary:
- Execution:
- Use the
http_requesttool to send a GET/POST request to the identified endpoint. - Example Request:
GET /wp-admin/admin-ajax.php?action=[ACTION]¶m=<script>alert(1)</script>&_wpnonce=[NONCE] HTTP/1.1 Host: localhost:8080
- Use the
6. Test Data Setup
- Install Plugin: Ensure
templates-and-addons-for-wpbakery-page-builderis installed and activated. - WPBakery dependency: This plugin usually requires WPBakery Page Builder to be active for its blocks to function. Ensure it is installed.
- Content Creation: Create a post containing a Business Template Block to ensure all frontend scripts/styles are loaded if the vulnerability is on the frontend.
7. Expected Results
- The HTTP response should have a
Content-Typeoftext/html. - The response body must contain the exact string
<script>alert(1)</script>(or the broken-out version) without HTML encoding (e.g., no<). - In a real browser, an alert box would appear.
8. Verification Steps
- Manual Verification: Use
http_requestto fetch the URL and check if the payload exists in the raw response body. - Automated Verification: Use
browser_navigateto the malicious URL and check for the presence of the alert using Playwright'spage.on('dialog', ...)or by checking for a side effect injected by the script (e.g.,window.pwned = 1).
9. Alternative Approaches
If no unauthenticated AJAX handlers are found:
- Search for
inithooks: Check if the plugin processes$_GETparameters on every page load to display "messages" or "errors".- Search Command:
grep -rn "add_action\s*(\s*['\"]init['\"]" .
- Search Command:
- Check for CSS/JS files: Occasionally, plugins have PHP files that act as dynamic CSS/JS (
style.php?color=...) which reflect input without proper headers or escaping. - WPBakery Admin XSS: Check if a logged-in Subscriber can use a shortcode that reflects attributes into the admin dashboard (Stored XSS escalated from Reflected).
Summary
The Business Template Blocks for WPBakery (Visual Composer) Page Builder plugin for WordPress is vulnerable to Reflected Cross-Site Scripting (XSS) in versions up to 1.3.2. This vulnerability stems from the plugin's failure to sanitize or escape user-controlled input before reflecting it back in an HTTP response, allowing unauthenticated attackers to execute arbitrary scripts in a user's browser.
Exploit Outline
1. Identify an endpoint that reflects user input, likely an unauthenticated AJAX action such as 'btb_load_template', 'btb_preview', or 'get_template_blocks' registered via wp_ajax_nopriv_ hooks. 2. Determine which GET or POST parameter (e.g., 'id', 'template', 'style', or 'class') is echoed directly into the page output. 3. Construct a malicious URL targeting wp-admin/admin-ajax.php with the 'action' set to the vulnerable handler and the targeted parameter containing a JavaScript payload (e.g., <script>alert(document.domain)</script>). 4. If the endpoint requires a security nonce, extract the valid nonce from the localized JavaScript objects on a page where the plugin is active (search for wp_localize_script output). 5. Distribute the crafted link to a victim; when clicked, the injected script executes within the context of the victim's browser session.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.