CVE-2025-68533

WC Builder <= 1.2.0 - Authenticated (Contributor+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
1.2.1
Patched in
10d
Time to patch

Description

The WC Builder plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.2.0 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with contributor-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:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.2.0
PublishedDecember 27, 2025
Last updatedJanuary 5, 2026
Affected pluginwc-builder

Source Code

WordPress.org SVN
Research Plan
Unverified

This plan outlines the research and exploitation steps for **CVE-2025-68533**, a Stored Cross-Site Scripting (XSS) vulnerability in the **WC Builder – WooCommerce Page Builder for WPBakery** plugin (versions <= 1.2.0). --- ### 1. Vulnerability Summary The "WC Builder" plugin extends WPBakery Page …

Show full research plan

This plan outlines the research and exploitation steps for CVE-2025-68533, a Stored Cross-Site Scripting (XSS) vulnerability in the WC Builder – WooCommerce Page Builder for WPBakery plugin (versions <= 1.2.0).


1. Vulnerability Summary

The "WC Builder" plugin extends WPBakery Page Builder with WooCommerce-specific elements. The vulnerability exists because the plugin registers several shortcodes/WPBakery elements that process user-supplied attributes but fail to sanitize them before storage or escape them before output. Specifically, a user with Contributor permissions can create a post containing a malicious shortcode attribute, which will execute arbitrary JavaScript in the context of any user (including Administrators) who views the post.

2. Attack Vector Analysis

  • Endpoint: wp-admin/post.php (Standard WordPress post editing) or wp-admin/post-new.php.
  • HTTP Parameter: content (Post content containing the malicious shortcode).
  • Authentication: Authenticated, Contributor-level access or higher.
  • Preconditions:
    • WPBakery Page Builder must be active.
    • The "WC Builder" plugin (<= 1.2.0) must be active.
    • The attacker must have permissions to create or edit posts (Contributor role is sufficient).

3. Code Flow (Inferred)

  1. Registration: The plugin uses add_shortcode() to register WooCommerce elements (e.g., Product Grid, Product Slider).
  2. Input: A Contributor saves a post. The shortcode and its attributes (e.g., title="<script>alert(1)</script>") are stored in the wp_posts table in the post_content column.
  3. Rendering: When a user views the post, the do_shortcode() function is called.
  4. Processing: The plugin's shortcode callback function (likely found in includes/ or elements/) retrieves the attributes using shortcode_atts().
  5. Sink: The callback function concatenates the attribute into an HTML string (e.g., an <h2> tag or a class attribute) and returns it or echos it without using esc_html(), esc_attr(), or wp_kses().

4. Nonce Acquisition Strategy

Since a Contributor is performing a standard post-update, they need the standard WordPress post nonce (_wpnonce).

  1. Login: Authenticate as a Contributor.
  2. Access Editor: Navigate to wp-admin/post-new.php.
  3. Extraction:
    • Use browser_navigate to load the page.
    • Use browser_eval to extract the nonce from the hidden input field:
      browser_eval("document.querySelector('#_wpnonce')?.value")
    • Also, extract the user_id and post_ID (if it's an existing draft).

5. Exploitation Strategy

Step 1: Identify Vulnerable Shortcodes

Search the plugin directory for registered shortcodes to find the exact names and parameters:

grep -rn "add_shortcode" /var/www/html/wp-content/plugins/wc-builder/

Look for callbacks that handle text-based attributes like title, sub_title, extra_class, or label.

Step 2: Craft the Payload

Construct a shortcode payload. Assuming a shortcode named [wcb_product_grid] with a title attribute:
[wcb_product_grid title='"><script>alert(document.domain)</script>']

Step 3: Inject via HTTP Request

Perform an http_request as the Contributor to save a new post.

  • URL: http://localhost:8080/wp-admin/post.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: editpost
    • post_ID: [NEW_POST_ID]
    • _wpnonce: [EXTRACTED_NONCE]
    • post_title: XSS Test
    • content: [wcb_product_grid title='"><script>alert(1)</script>']
    • post_status: publish (Note: Contributors can only set to pending, but the XSS will still fire in the preview or when an Admin views the pending post).

Step 4: Trigger the XSS

Login as an Administrator and navigate to the newly created post (or its preview/edit page).

6. Test Data Setup

  1. Plugin Setup: Ensure wc-builder v1.2.0 is installed and active.
  2. User Setup: Create a user with the contributor role.
  3. Target Post: As Contributor, initiate a new post to generate a post_ID and the necessary nonce.

7. Expected Results

  • The POST request to post.php should return a 302 Redirect.
  • When the post is viewed (frontend or via wp-admin), the HTML source should reveal the payload reflected without escaping:
    <div class="wcb-grid-title">"><script>alert(1)</script></div>
  • The browser should execute the alert(1) script.

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the content is stored:
    wp post get [POST_ID] --field=post_content
    
  2. Frontend Verification: Navigate to the post URL as an unauthenticated user or Admin and check for the script execution in the DOM.

9. Alternative Approaches

  • WPBakery AJAX: If the plugin uses a specific AJAX action for saving element data, use grep -r "wp_ajax_" to find the handler.
  • Attribute Breakout: If the payload is reflected inside an HTML attribute (e.g., class="..."), use a breakout payload:
    class='x" onmouseover="alert(1)" data-x="'
  • Shortcode in Meta: Some builders store element data in Post Meta (e.g., _vc_post_settings). Check if the plugin saves attributes to meta and then renders them unescaped in the frontend template.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WC Builder plugin for WordPress is vulnerable to Stored Cross-Site Scripting via WPBakery element shortcodes in versions up to 1.2.0. The plugin fails to sanitize or escape user-supplied attributes like 'title' or 'extra_class' before outputting them in HTML, allowing authenticated users with Contributor-level access to inject malicious JavaScript into pages.

Vulnerable Code

// Inferred from plugin shortcode registration and rendering logic
// File path: includes/elements/product-grid.php

public function render($atts, $content = null) {
    $atts = shortcode_atts(array(
        'title' => '',
        'extra_class' => ''
    ), $atts);

    $output = '<div class="wc-builder-element ' . $atts['extra_class'] . '">';
    if ($atts['title']) {
        $output .= '<h3 class="title">' . $atts['title'] . '</h3>';
    }
    // ...
    return $output;
}

Security Fix

--- includes/elements/product-grid.php
+++ includes/elements/product-grid.php
@@ -10,1 +10,1 @@
-    $output = '<div class="wc-builder-element ' . $atts['extra_class'] . '">';
+    $output = '<div class="wc-builder-element ' . esc_attr($atts['extra_class']) . '">';
@@ -12,1 +12,1 @@
-        $output .= '<h3 class="title">' . $atts['title'] . '</h3>';
+        $output .= '<h3 class="title">' . esc_html($atts['title']) . '</h3>';

Exploit Outline

The vulnerability is exploited by an authenticated Contributor who can create or edit posts. The attacker first captures a valid WordPress post nonce and a post ID. They then submit a POST request to the 'wp-admin/post.php' endpoint with the 'action' set to 'editpost'. In the 'content' field, the attacker includes a plugin-specific shortcode and crafts a malicious payload within its attributes, such as title='<script>alert(1)</script>'. When a site administrator views the post (either in the editor or on the frontend), the unsanitized attribute is rendered directly into the page, triggering the script execution.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.