CVE-2026-24584

Tutor LMS BunnyNet Integration <= 1.0.0 - Authenticated (Tutor instructor+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
1.0.1
Patched in
58d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.0.0
PublishedJanuary 19, 2026
Last updatedMarch 17, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

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 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.php or wp-admin/post.php.
  • Action (Inferred): The plugin likely uses an AJAX action such as tutor_bunnynet_save_settings or hooks into save_post via the Tutor LMS lesson/course editor.
  • Vulnerable Parameter: Likely parameters include bunnynet_library_id, bunnynet_pull_zone, or bunnynet_video_id.
  • Authentication: Authenticated with tutor_instructor role or higher.
  • Preconditions: The Tutor LMS plugin must be active, and the BunnyNet Integration plugin enabled.

3. Code Flow (Inferred)

  1. Entry Point: An instructor navigates to the Tutor LMS settings for Bunny.net or edits a lesson to add a Bunny.net video.
  2. Processing: The instructor submits a form or triggers an AJAX request containing the payload.
  3. Storage: The plugin receives the input and uses update_option() or update_post_meta() without applying sanitize_text_field() or wp_kses().
  4. Sink: When a student or administrator views the lesson/course, the plugin retrieves the value using get_option() or get_post_meta() and echoes it directly into the HTML (e.g., inside a data- attribute of a video player or a src attribute) without esc_attr() or esc_url().

4. Nonce Acquisition Strategy

To exploit AJAX-based settings, a nonce is required.

  1. Identify Shortcode/Page: Identify the Tutor LMS settings page where Bunny.net is configured. This is usually wp-admin/admin.php?page=tutor-settings.
  2. Navigate: Use browser_navigate to access the settings page as an Instructor.
  3. Variable Extraction: The plugin likely localizes a script using wp_localize_script. Look for global objects like tutor_bunnynet_data or tutor_admin_params.
  4. JS Command:
    // Example based on Tutor LMS patterns
    browser_eval("window.tutor_admin_params?.nonce || window.tutor_bunnynet_data?.nonce")
    
  5. Verify Action: Check the wp_create_nonce() call in the source. If it uses a specific action (e.g., tutor_bunnynet_action), ensure the browser_eval targets 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

  1. Instructor User: Create a user with the tutor_instructor role using WP-CLI.
    wp user create instructor instructor@example.com --role=tutor_instructor --user_pass=password
    
  2. 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]
    
  3. Enable Integration: Ensure the BunnyNet Integration is toggled "ON" in Tutor LMS settings.

7. Expected Results

  • Storage: The response from the admin-ajax.php request 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

  1. 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]
    
  2. 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.php with action=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 onload handler.
  • Pull Zone URL: If the "Pull Zone URL" field is vulnerable, use a javascript: protocol if it is rendered within an <a> tag or src attribute.
    • Payload: javascript:alert(1) (if reflected in a way that allows execution).
Research Findings
Static analysis — not yet PoC-verified

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

--- a/includes/Admin/Settings.php
+++ b/includes/Admin/Settings.php
@@ -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);
     }
 
--- a/includes/Frontend/Player.php
+++ b/includes/Frontend/Player.php
@@ -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.