Bricksable for Bricks Builder <= 1.6.83 - Authenticated (Author+) Stored Cross-Site Scripting
Description
The Bricksable for Bricks Builder plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.6.83 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with author-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:NTechnical Details
What Changed in the Fix
Changes introduced in v1.6.84
Source Code
WordPress.org SVN# Research Plan: CVE-2026-56009 - Bricksable for Bricks Builder Stored XSS ## 1. Vulnerability Summary The **Bricksable for Bricks Builder** plugin (<= 1.6.83) is vulnerable to **Authenticated Stored Cross-Site Scripting (XSS)**. The plugin registers several custom elements for the Bricks Page Buil…
Show full research plan
Research Plan: CVE-2026-56009 - Bricksable for Bricks Builder Stored XSS
1. Vulnerability Summary
The Bricksable for Bricks Builder plugin (<= 1.6.83) is vulnerable to Authenticated Stored Cross-Site Scripting (XSS). The plugin registers several custom elements for the Bricks Page Builder. These elements (e.g., Multi Heading, Icon List, Card, Back To Top) define various input controls (text, textarea, etc.) in their set_controls() methods.
The vulnerability exists because the plugin fails to sanitize these inputs when they are saved via the Bricks Builder and, more importantly, fails to escape the values when they are rendered in the render() method of the element classes. An attacker with Author level access or higher can use the Bricks Builder to insert a Bricksable element and inject malicious JavaScript into one of the element's settings. This script is then stored in the post's metadata and executes in the context of any user (including Administrators) who views the affected page or opens it in the builder.
2. Attack Vector Analysis
- Target Endpoint: WordPress AJAX handler
admin-ajax.php. - Action:
bricks_save_post(The standard Bricks Builder save action). - Vulnerable Parameters: The
elementsJSON object within the POST body, specifically within thesettingsof Bricksable elements. - Authentication: Required. Role: Author or higher (any role capable of using the Bricks Builder to edit a post).
- Preconditions:
- Bricks Builder plugin must be active.
- Bricksable for Bricks Builder plugin must be active.
- The attacker must have permissions to edit a post/page using the Bricks Builder.
3. Code Flow
- Definition: Elements like
Bricksable_Multi_Heading(inincludes/elements/multi-heading/element-multi-heading.php) register controls. For example, themulti_heading_itemrepeater contains atextfield:'text' => array( 'type' => 'text', 'hasDynamicData' => 'text', ), - Storage: When a user saves a page in Bricks, the element's settings (including the
textfield) are sent via thebricks_save_postAJAX action and stored as JSON in the_bricks_page_contentpost meta. - Rendering (The Sink): When the page is viewed, Bricks calls the
render()method of the element class. Although therender()methods are truncated in the provided source, the vulnerability description confirms that these settings are output without proper escaping (e.g., usingesc_html()orwp_kses()). - Execution: The stored script is rendered directly into the HTML of the page and executed by the victim's browser.
4. Nonce Acquisition Strategy
To exploit bricks_save_post, a valid bricks-nonce is required. This nonce is tied to the Bricks Builder session.
- Setup: The PoC agent should create a post and ensure it is "Bricks-enabled".
- Navigate: Use the
browser_navigatetool to go to the Bricks Builder interface for that post:http://<wp-url>/wp-admin/post.php?post=<POST_ID>&bricks=run - Extract: Use the
browser_evaltool to extract the nonce and current page data from the globalbricksDataobject:// The nonce is typically stored here const nonce = window.bricksData?.nonce; // We also need the current elements structure to ensure a valid save request const pageData = window.bricksData?.pageData; return { nonce, pageData };
5. Exploitation Strategy
The goal is to update a post's content with a malicious ba-multi-heading element.
Step-by-Step Plan:
- Login: Authenticate as an Author user.
- Find Post: Identify a post ID owned by the Author or create a new one.
- Get Nonce: Navigate to the Bricks Builder page for that ID and extract
bricksData.nonce. - Construct Payload: Create a JSON structure for a
ba-multi-headingelement where thetextfield contains the XSS payload.[ { "name": "ba-multi-heading", "settings": { "multi_heading_item": [ { "text": "Normal Title <script>alert(document.domain)</script>" } ] } } ] - Execute Injection: Send a POST request to
admin-ajax.php.- URL:
http://<wp-url>/wp-admin/admin-ajax.php - Content-Type:
application/x-www-form-urlencoded - Body:
action=bricks_save_post postId=<POST_ID> nonce=<EXTRACTED_NONCE> elements=<URL_ENCODED_JSON_PAYLOAD>
- URL:
- Verify: Navigate to the frontend URL of the post and check if the
alerttriggers.
6. Test Data Setup
- User: Create a user with the
authorrole. - Post: Create a post (e.g., ID 123) and set its
post_statustopublish. - Bricks Initialization: Ensure the post is set to use Bricks. This can be done by editing it once in the builder or setting post meta
_bricks_editor_modetotrue.
7. Expected Results
- The
bricks_save_postrequest should return a success status (usually{"success": true}). - When viewing the post frontend, the HTML source should contain the raw
<script>alert(document.domain)</script>tag within theba-multi-headingelement container. - The browser should execute the script.
8. Verification Steps
- HTTP Verification: Observe the response from the frontend request to ensure the payload is present in the HTML.
- Database Verification (CLI):
Check if the JSON in the metadata contains the injected script.wp post meta get <POST_ID> _bricks_page_content
9. Alternative Approaches
If Multi Heading is patched or difficult to target, try other Bricksable elements identified in the source:
- Icon List (
ba-icon-list): Inject intoitems->title. - Card (
ba-card): Inject into thebadgecontrol. - Content Toggle (
ba-content-toggle): Inject intocontentToggleItem->labelorcontent. - Back To Top (
ba-back-to-top): Inject into thetextcontrol.
The exploitation mechanism (Bricks AJAX save) remains the same for all these elements.
Summary
The Bricksable for Bricks Builder plugin for WordPress is vulnerable to Authenticated Stored Cross-Site Scripting (XSS) due to a lack of output escaping in multiple element rendering methods. An attacker with Author-level permissions or higher can inject malicious scripts into element settings like "Multi Heading," "Card," or "Icon List," which then execute in the context of any user viewing the page or editing it in the builder.
Vulnerable Code
// includes/elements/back-to-top/element-back-to-top.php line 518 if ( isset( $settings['text'] ) ) { $output .= "<span {$this->render_attributes( 'text' )}>"; $output .= $settings['text']; $output .= '</span>'; } --- // includes/elements/multi-heading/element-multi-heading.php line 337 // Heading. if ( isset( $item['use_background_text_mask'] ) ) { $output .= '<' . $this->render_attributes( "multi-heading-item-$index" ) . '><' . $this->render_attributes( "multi-heading-item-text-mask-$index" ) . '>' . $item['text'] . '</span></span>'; } else { $output .= '<' . $this->render_attributes( "multi-heading-item-$index" ) . '>' . $item['text'] . '</span>'; } --- // includes/elements/icon-list/element-icon-list.php line 1029 if ( isset( $list_item['link'] ) ) { $this->set_link_attributes( "a-$index", $list_item['link'] ); $output .= '<a ' . $this->render_attributes( "a-$index" ) . '><' . $this->render_attributes( "title-$index" ) . '>' . $list_item['title'] . '</' . $title_tag . '></a>'; } else { $output .= '<' . $this->render_attributes( "title-$index" ) . '>' . $list_item['title'] . '</' . $title_tag . '>'; }
Security Fix
@@ -515,7 +515,7 @@ $this->set_attribute( 'text', 'class', 'ba-back-to-top-text' ); if ( isset( $settings['text'] ) ) { $output .= "<span {$this->render_attributes( 'text' )}>"; - $output .= $settings['text']; + $output .= esc_html( $settings['text'] ); $output .= '</span>'; } } elseif ( method_exists( '\Bricks\Frontend', 'render_children' ) ) {
Exploit Outline
To exploit this vulnerability, an authenticated user with Author-level access (capable of using the Bricks Builder) needs to perform the following steps: 1. Login and navigate to the Bricks Builder editor for a post the user is authorized to edit. 2. Obtain the valid 'bricks-nonce' by inspecting the global 'bricksData' object in the browser console. 3. Construct a malicious JSON payload representing a Bricksable element (e.g., 'ba-multi-heading') where a text field like 'text' contains a Cross-Site Scripting payload such as <script>alert(document.domain)</script>. 4. Send an AJAX POST request to 'wp-admin/admin-ajax.php' with the action set to 'bricks_save_post', providing the 'postId', the 'nonce', and the 'elements' JSON payload. 5. Once the post is saved, any user who views the post on the frontend will trigger the execution of the injected script because the plugin renders the stored setting without proper HTML escaping.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.