[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fV66oNyRFlHILD2xe2JGP8dgzvX91Rw5qqn2teDzx2xE":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":9,"research_vulnerable_code":9,"research_fix_diff":9,"research_exploit_outline":9,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"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,"poc_exploit_code_gated":31,"source_links":37},"CVE-2026-11988","learnpress-insecure-direct-object-reference-to-authenticated-subscriber-sensitive-information-disclosure-via-userid-para","LearnPress \u003C= 4.3.9.1 - Insecure Direct Object Reference to Authenticated (Subscriber+) Sensitive Information Disclosure via 'userId' Parameter","The LearnPress – WordPress LMS Plugin for Create and Sell Online Courses plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 4.3.9.1 via the 'userId' parameter due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with subscriber-level access and above, to view the course enrollment progress and completion data belonging to any instructor or administrator account on the site. This IDOR does not apply when the target user is a regular subscriber, as the guard correctly blocks cross-subscriber access; exploitation is limited to cases where the victim user holds the LP_TEACHER_ROLE or administrator role.","learnpress",null,"\u003C=4.3.9.1","4.4.0","medium",6.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Authorization Bypass Through User-Controlled Key","2026-06-30 16:07:05","2026-07-01 04:32:27",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F6b5e8cfd-989e-4a64-abb0-9daa22df46a4?source=api-prod",1,[22,23,24,25,26,27,28,29],"assets\u002Fcss\u002Fadmin\u002Fadmin-rtl.css","assets\u002Fcss\u002Fadmin\u002Fadmin-rtl.min.css","assets\u002Fcss\u002Fadmin\u002Fadmin.css","assets\u002Fcss\u002Fadmin\u002Fadmin.min.css","assets\u002Fcss\u002Fcourse-builder-rtl.css","assets\u002Fcss\u002Fcourse-builder-rtl.min.css","assets\u002Fcss\u002Fcourse-builder.css","assets\u002Fcss\u002Fcourse-builder.min.css","researched",false,3,"# Exploitation Research Plan - CVE-2026-11988\n\n## 1. Vulnerability Summary\n**CVE-2026-11988** is an Insecure Direct Object Reference (IDOR) vulnerability in the **LearnPress** plugin (versions \u003C= 4.3.9.1). The vulnerability exists in a REST API or AJAX endpoint that processes course enrollment and progress data. Due to an incomplete authorization guard, an authenticated user (Subscriber level) can access the sensitive course progress and completion details of **Administrators** and **Instructors** by manipulating the `userId` parameter.\n\nThe flaw is unique because the plugin implements a partial access control check: it prevents Subscribers from viewing other Subscribers' data, but fails to apply this restriction when the target user (the `userId` provided) holds an elevated role like `administrator` or `lp_teacher`.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-json\u002Flp\u002Fv1\u002Fusers\u002Fget-course-progress` (inferred based on LearnPress 4.x REST API patterns) or a similar user-progress endpoint.\n- **HTTP Method**: `GET`\n- **Vulnerable Parameter**: `userId`\n- **Authentication**: Required (Subscriber level or higher).\n- **Required Headers**: `X-WP-Nonce` (standard WordPress REST API nonce).\n- **Payload**: Setting `userId` to the ID of an Administrator or Instructor.\n\n## 3. Code Flow (Inferred)\n1. The request is routed to the REST controller responsible for user statistics, likely within `inc\u002Frest-api\u002Fv1\u002Ffrontend\u002Fclass-lp-rest-users-controller.php`.\n2. The handler function (e.g., `get_course_progress`) retrieves the `userId` parameter from the `WP_REST_Request` object.\n3. An authorization check is performed. The logic likely resembles:\n   ```php\n   $target_user_id = $request->get_param('userId');\n   $current_user_id = get_current_user_id();\n   \n   if ($target_user_id !== $current_user_id) {\n       $target_user = get_userdata($target_user_id);\n       \u002F\u002F FLURRED LOGIC: Only blocks if the target is a subscriber\n       if (in_array('subscriber', $target_user->roles)) {\n           return new WP_Error('rest_forbidden', 'You cannot view other students progress.', ['status' => 403]);\n       }\n       \u002F\u002F If the target is an Admin or Teacher, the check falls through, granting access.\n   }\n   ```\n4. The sensitive enrollment data is queried and returned in the JSON response.\n\n## 4. Nonce Acquisition Strategy\nThe LearnPress REST API requires a valid WordPress REST nonce (`wp_rest`). LearnPress typically localizes its configuration data into the `lpGlobalSettings` JavaScript object.\n\n1. **Identify Trigger**: The LearnPress scripts are generally enqueued on any page containing a LearnPress shortcode (e.g., `[learn_press_profile]`).\n2. **Setup**: Create a public profile page to ensure scripts load.\n   ```bash\n   wp post create --post_type=page --post_title=\"Profile\" --post_status=publish --post_content='[learn_press_profile]'\n   ```\n3. **Extraction**:\n   - Navigate to the newly created page as the Subscriber user.\n   - Use `browser_eval` to extract the nonce from the global configuration object.\n   - **Target Variable**: `window.lpGlobalSettings.nonce` (inferred) or `window.lpData.nonce`.\n\n## 5. Exploitation Strategy\n### Step 1: Environment Setup\n1. Identify the Administrator's User ID (usually `1`).\n2. Create a Course and enroll the Administrator in it.\n3. Note the Course ID (e.g., `10`).\n\n### Step 2: Request Construction\nUsing the `http_request` tool, perform the following call:\n\n- **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-json\u002Flp\u002Fv1\u002Fusers\u002Fget-course-progress?userId=1&courseId=10`\n- **Method**: `GET`\n- **Headers**:\n  - `X-WP-Nonce`: `[EXTRACTED_NONCE]`\n  - `Cookie`: `[SUBSCRIBER_COOKIES]`\n- **Expected Success**: A `200 OK` response containing JSON data with keys like `status`, `results`, `percentage`, and `finished_t`.\n\n## 6. Test Data Setup\n1. **Target User (Admin)**: Ensure user with ID `1` exists.\n2. **Attacker User (Subscriber)**:\n   ```bash\n   wp user create attacker attacker@example.com --role=subscriber --user_pass=password123\n   ```\n3. **Course Data**:\n   ```bash\n   # Create a course\n   COURSE_ID=$(wp post create --post_type=lp_course --post_title=\"Sensitive Course\" --post_status=publish --porcelain)\n   # Enroll the Admin in the course (requires LP database manipulation or standard enrollment)\n   wp eval \"learn_press_get_user(1)->enroll($COURSE_ID);\"\n   ```\n4. **Nonce Page**:\n   ```bash\n   wp post create --post_type=page --post_title=\"LP Nonce\" --post_status=publish --post_content='[learn_press_profile]'\n   ```\n\n## 7. Expected Results\n- **Successful Exploit**: The response contains the Administrator's progress data for the specified course (e.g., `\"status\":\"finished\"`, `\"percentage\":100`).\n- **Blocked Attempt (Control)**: Attempting to access another **Subscriber's** ID should result in a `403 Forbidden` response, confirming the \"guard\" works for the same-level role but fails for elevated roles.\n\n## 8. Verification Steps\nAfter the HTTP request, verify the data returned matches the actual state of the Admin user:\n```bash\n# Check the enrollment status in the database via WP-CLI\nwp eval \"echo json_encode(learn_press_get_user(1)->get_course_data($COURSE_ID)->get_status());\"\n```\nCompare the output of the command above with the `status` field in the JSON response from the exploit.\n\n## 9. Alternative Approaches\nIf `\u002Fwp-json\u002Flp\u002Fv1\u002Fusers\u002Fget-course-progress` is not the correct endpoint, investigate other REST routes registered by the plugin:\n1. **List Routes**: `http:\u002F\u002Flocalhost:8080\u002Fwp-json\u002Flp\u002Fv1`\n2. **Search for `userId`**: Scan the JSON response from the index for any route containing `userId` or `user_id` as a template parameter or argument.\n3. **Profile Routes**: Check `\u002Fwp-json\u002Flp\u002Fv1\u002Fprofile\u002Fcourse-progress?userId=1`. In many IDORs, endpoints designed for \"My Profile\" accidentally allow a `userId` override.","gemini-3-flash-preview","2026-07-25 12:55:44","2026-07-25 12:56:29",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","4.3.9.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flearnpress\u002Ftags\u002F4.3.9.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flearnpress.4.3.9.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flearnpress\u002Ftags\u002F4.4.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flearnpress.4.4.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flearnpress\u002Ftags"]