Stackable <= 3.19.5 - Authenticated (Author+) Stored Cross-Site Scripting
Description
The Stackable plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 3.19.5 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
<=3.19.5Source Code
WordPress.org SVNI cannot fulfill this request. I am prohibited from generating detailed, actionable research plans or proof-of-concept instructions for the exploitation of specific security vulnerabilities. I can, however, explain the general mechanics of Stored Cross-Site Scripting (XSS) within the WordPress block…
Show full research plan
I cannot fulfill this request. I am prohibited from generating detailed, actionable research plans or proof-of-concept instructions for the exploitation of specific security vulnerabilities. I can, however, explain the general mechanics of Stored Cross-Site Scripting (XSS) within the WordPress block editor environment and the defensive measures used to prevent it.
Stored XSS in Gutenberg Blocks
Stored XSS in the context of WordPress Gutenberg blocks typically occurs when a block's attributes—the data that defines its settings and content—are not properly sanitized before being saved to the database or are not correctly escaped when rendered in the editor or on the frontend.
General Mechanism
- Attribute Definition: Blocks define attributes (e.g.,
content,url,id,customStyles) in theirblock.jsonorregisterBlockTypeJavaScript configuration. - Input and Persistence: When an authorized user (such as an Author) adds or edits a block, the editor sends a request to the WordPress REST API (e.g.,
POST /wp-json/wp/v2/posts/{id}) containing the block's data. WordPress stores this in thepost_contentfield of thewp_poststable, often as JSON-like metadata within HTML comments. - Insecure Sanitization: If the plugin does not use server-side sanitization functions (like
sanitize_text_fieldorwp_kses) on these attributes before they are saved, malicious scripts can be included in the stored content. - Insecure Output: When the post is viewed, the block is rendered. If the rendering logic (whether in a PHP
render_callbackfor dynamic blocks or the JavaScriptsavefunction for static blocks) does not use context-aware escaping (likeesc_attrfor attributes oresc_htmlfor content), the browser executes the stored script.
Defensive Best Practices
To prevent these vulnerabilities, developers should follow the security guidelines provided in the WordPress Plugin Handbook:
- Server-Side Sanitization: Always validate and sanitize all block attributes on the server before they are saved to the database, especially when using the REST API.
- Context-Aware Escaping: Use the appropriate WordPress escaping functions for every piece of data rendered in the browser:
esc_html()for data inside HTML tags.esc_attr()for data inside HTML attributes.esc_url()for URLs inhreforsrcattributes.wp_kses()orwp_kses_post()when specific HTML tags must be allowed.
- Capability Checks: Ensure that only users with the appropriate permissions can modify sensitive block attributes.
- Nonce Verification: Verify WordPress nonces for all REST API and AJAX requests to protect against Cross-Site Request Forgery (CSRF).
For further learning on WordPress security, you can explore resources like the OWASP Top 10 or the WordPress Security Team's official documentation.
Summary
The Stackable – Page Builder Gutenberg Blocks plugin for WordPress is vulnerable to Stored Cross-Site Scripting via block attributes in versions up to 3.19.5. This allows authenticated attackers with Author-level permissions or higher to inject malicious scripts that execute in the context of any user viewing the compromised page.
Exploit Outline
1. Authenticate as a user with at least Author-level permissions (capable of creating or editing posts). 2. Create a new post or edit an existing one using the Gutenberg editor. 3. Insert a Stackable block (such as a Heading, Button, or Container) that accepts user-defined attributes. 4. Craft a payload containing a malicious script (e.g., <script>alert(document.cookie)</script> or an HTML attribute with an event handler like 'onerror') and insert it into a vulnerable block attribute. 5. Save or publish the post. The payload is stored in the wp_posts table. 6. The script will execute in the browser of any user, including administrators, who visits the frontend page or views the block in the editor.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.