UX Flat <= 5.4.0 - Authenticated (Contributor+) Stored Cross-Site Scripting
Description
The UX Flat plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 5.4.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:NTechnical Details
# Research Plan: CVE-2026-24576 UX Flat Stored XSS ## 1. Vulnerability Summary The **UX Flat** plugin (up to version 5.4.0) contains a Stored Cross-Site Scripting (XSS) vulnerability. This flaw exists because the plugin fails to properly sanitize user-supplied input and escape output when rendering…
Show full research plan
Research Plan: CVE-2026-24576 UX Flat Stored XSS
1. Vulnerability Summary
The UX Flat plugin (up to version 5.4.0) contains a Stored Cross-Site Scripting (XSS) vulnerability. This flaw exists because the plugin fails to properly sanitize user-supplied input and escape output when rendering specific plugin-defined elements, likely through shortcodes or custom post meta. Authenticated users with Contributor-level permissions or higher can inject malicious scripts into WordPress posts or pages. When these pages are viewed by other users (including administrators), the scripts execute in their browser context.
2. Attack Vector Analysis
- Endpoint: WordPress Post Editor (Gutenberg or Classic) or AJAX handlers for plugin-specific metadata.
- Vulnerable Component: Likely a Shortcode callback or a page builder element renderer.
- Payload Carrier: Shortcode attributes (e.g.,
title,content,url) or Post Meta values. - Authentication Level: Contributor+ (has
edit_postscapability). - Preconditions: The plugin
ux-flatmust be active. A Contributor user must be able to save a post (even as a draft/pending review).
3. Code Flow (Inferred)
- Registration: The plugin registers a shortcode or a block via
add_shortcode('ux_flat_...', 'render_function')or registers a meta box. - Input: A Contributor user creates a post and includes the shortcode with a malicious attribute:
[ux_flat_element title='<script>alert(1)</script>']. - Storage: WordPress saves the post content (including the raw shortcode string) to the
wp_poststable. - Execution (Sink): When any user views the post, WordPress parses the shortcode and calls the plugin's rendering function.
- Vulnerability: Inside the rendering function, the code retrieves the attribute:
function render_function( $atts ) { $a = shortcode_atts( array( 'title' => '' ), $atts ); return "<div>" . $a['title'] . "</div>"; // VULNERABLE: No esc_html() } - Output: The unsanitized payload is sent to the browser.
4. Nonce Acquisition Strategy
Shortcodes typically do not require nonces for insertion into post content because the security boundary is the edit_posts capability. However, if the vulnerability exists in a custom AJAX "Save" action for a plugin-specific settings panel:
- Identify Action: Search for
wp_ajax_hooks in the plugin. - Localization: Look for
wp_localize_scriptin the plugin code to find the nonce variable. - Extraction:
- Create a post with the plugin's shortcode:
wp post create --post_type=page --post_status=publish --post_content='[ux_flat_element]'. - Navigate to the page:
browser_navigate("http://localhost:8080/test-page"). - Extract the nonce via
browser_eval:browser_eval("window.ux_flat_params?.nonce").
- Create a post with the plugin's shortcode:
Note: If the vulnerability is in a shortcode, no nonce is required for the HTTP request.
5. Exploitation Strategy
Primary Goal: Inject Stored XSS via Shortcode
- Discover Shortcodes: Use
grep -r "add_shortcode" wp-content/plugins/ux-flat/to find available shortcodes. Let's assume a discovered shortcode is[ux_flat_box]. - Construct Payload:
[ux_flat_box title='<script>alert(document.domain)</script>']- If attributes are used in HTML attributes:
[ux_flat_box link='"><script>alert(1)</script>']
- Submit Request: Use the
http_requesttool to create a "Pending Review" post as a Contributor.
HTTP Request (Example):
- Method: POST
- URL:
http://localhost:8080/wp-admin/post.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action=editpost post_ID=[POST_ID] post_title=XSS Test content=[ux_flat_box title='<script>alert(1)</script>'] _wpnonce=[NONCE_FROM_PAGE_SOURCE]
- Trigger: Navigate to the post URL (or preview URL) as an Administrator to trigger the execution.
6. Test Data Setup
- Install Plugin: Ensure
ux-flat<= 5.4.0 is installed and active. - Create Contributor:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Identify Post ID: Create a blank post to get an ID for the
editpostaction:wp post create --post_type=post --post_status=draft --post_author=[ATTACKER_ID]
7. Expected Results
- The shortcode is processed by WordPress.
- The plugin's rendering function outputs the
titleattribute raw. - When the page is loaded, the browser executes
alert(1). - Viewing the page source shows:
<div><script>alert(1)</script></div>instead of<script>.
8. Verification Steps
- Verify Storage:
wp db query "SELECT post_content FROM wp_posts WHERE post_title='XSS Test'" - Check Output:
Usehttp_requestto GET the post URL and check if the payload is present and unescaped in the HTML body. - Confirm Execution:
Usebrowser_navigateto the post URL and check for an alert dialog or a console log injected via the script.
9. Alternative Approaches
- Post Meta Injection: If the plugin uses a custom meta box, use the
wp_ajax_save_postoreditpostlogic to inject into meta fields. Check forupdate_post_metacalls in the plugin that lacksanitize_text_field. - Attribute Breakout: If the input is placed inside an attribute (e.g.,
<div data-title="INPUT">), use"><script>alert(1)</script>to break out of the tag. - Gutenberg Blocks: If the plugin uses Gutenberg, check the
attributesinregisterBlockTypeand see if thesaveoreditfunctions usedangerouslySetInnerHTMLor lack escaping in the PHPrender_callback.
Summary
The UX Flat plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via shortcode attributes in versions up to 5.4.0. Authenticated attackers with Contributor-level permissions or higher can inject malicious JavaScript into posts, which executes in the browser context of any user viewing the page.
Vulnerable Code
// Inferred from research plan - exact file path and line numbers unknown function render_function( $atts ) { $a = shortcode_atts( array( 'title' => '' ), $atts ); return "<div>" . $a['title'] . "</div>"; // VULNERABLE: No esc_html() applied to user-controlled attribute }
Security Fix
@@ -10,1 +10,1 @@ - return "<div>" . $a['title'] . "</div>"; + return "<div>" . esc_html($a['title']) . "</div>";
Exploit Outline
To exploit this vulnerability, an attacker requires at least Contributor-level access to the WordPress dashboard. The attacker first identifies a shortcode registered by the UX Flat plugin (such as [ux_flat_box]). They then create a new post or edit an existing one, inserting the shortcode with a malicious payload in one of its attributes, for example: [ux_flat_box title='<script>alert(document.domain)</script>']. Once the post is saved or submitted for review, the script is stored in the database. When an administrator or any other user views the post or the post preview, the browser executes the injected script because the plugin fails to sanitize or escape the attribute value during the rendering process.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.