CVE-2025-14798

LearnPress – WordPress LMS Plugin <= 4.3.2.4 - Missing Authorization to Unauthenticated Sensitive User Information Disclosure via REST API

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
4.3.2.5
Patched in
1d
Time to patch

Description

The LearnPress – WordPress LMS Plugin for WordPress is vulnerable to Sensitive Information Exposure in versions up to, and including, 4.3.2.4 via the get_item_permissions_check function. This makes it possible for unauthenticated attackers to extract sensitive data including user first names and last names. Other information such as social profile links and enrollment are also included.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=4.3.2.4
PublishedJanuary 19, 2026
Last updatedJanuary 20, 2026
Affected pluginlearnpress

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-14798 ## 1. Vulnerability Summary The **LearnPress** plugin for WordPress (versions <= 4.3.2.4) contains a missing authorization vulnerability within its REST API implementation. Specifically, the `get_item_permissions_check` method in a REST controller (like…

Show full research plan

Exploitation Research Plan - CVE-2025-14798

1. Vulnerability Summary

The LearnPress plugin for WordPress (versions <= 4.3.2.4) contains a missing authorization vulnerability within its REST API implementation. Specifically, the get_item_permissions_check method in a REST controller (likely LP_REST_Users_Controller or LP_REST_Profile_Controller) fails to properly validate the requester's identity or permissions. This allows unauthenticated attackers to query user-specific endpoints and retrieve sensitive Personally Identifiable Information (PII), including first names, last names, social media profile links, and course enrollment status of any registered user.

2. Attack Vector Analysis

  • Endpoint: /wp-json/lp/v1/users/<id> (inferred from plugin structure) or /wp-json/lp/v1/profile/<id>.
  • Method: GET
  • Authentication: None required (Unauthenticated).
  • Vulnerable Parameter: The id path variable representing the target User ID.
  • Preconditions: The plugin LearnPress must be active. At least one user (other than the admin) should exist with populated profile data to demonstrate sensitivity.

3. Code Flow

  1. Route Registration: The plugin registers REST routes in inc/rest-api/v1/frontend/class-lp-rest-users-controller.php (or similar) using register_rest_route.
  2. Permission Callback: The route for fetching a user item (GET) is configured with a 'permission_callback' => array( $this, 'get_item_permissions_check' ).
  3. The Vulnerability: Inside get_item_permissions_check($request), the code returns true without checking is_user_logged_in() or verifying if the requester has the edit_users capability or if they are requesting their own data.
  4. Data Retrieval: The get_item($request) method is then called. It retrieves the user object and passes it through a preparer/serializer that includes fields like first_name, last_name, social_links, and enrolled_courses.
  5. Information Leak: The prepared data is returned in the JSON response to the unauthenticated requester.

4. Nonce Acquisition Strategy

While WordPress REST API endpoints typically require a _wpnonce (action wp_rest) for authenticated requests (to prevent CSRF), unauthenticated GET requests to public-facing REST routes often do not require a nonce unless specifically enforced by the permission_callback.

If the endpoint returns a 403 Forbidden with a "rest_cookie_invalid_nonce" error, use the following strategy:

  1. Identify Script Loading: LearnPress typically enqueues its localized scripts on its profile page. The shortcode [learn_press_profile] is the primary trigger.
  2. Setup: Create a "Profile" page:
    wp post create --post_type=page --post_title="LP Profile" --post_status=publish --post_content='[learn_press_profile]'
  3. Acquisition:
    • Navigate to the new page.
    • Use browser_eval to extract the LearnPress settings object:
      browser_eval("window.lpGlobalSettings?.nonce") or browser_eval("window.lpData?.nonce").
    • Verbatim check: Search lp-main.js or the page source for lpGlobalSettings or learn_press_js_localize.

5. Exploitation Strategy

  1. Target Identification: We will attempt to disclose information for User ID 2 (usually the first user created after the admin).
  2. Request: Perform an unauthenticated GET request to the LearnPress User REST endpoint.
  3. Tooling: Use http_request.

Request Structure:

  • URL: http://<target>/wp-json/lp/v1/users/2
  • Method: GET
  • Headers: Accept: application/json

Expected Response:
A JSON object containing:

  • id: 2
  • first_name: "..."
  • last_name: "..."
  • social_links: { ... }
  • enrolled_courses: [ ... ]

6. Test Data Setup

  1. Create Victim User:
    wp user create victim victim@example.com --role=subscriber --user_pass=password123
  2. Populate Meta:
    wp user meta update 2 first_name "Sensitive"
    wp user meta update 2 last_name "Information"
    wp user meta update 2 _lp_social_links '{"facebook":"https://facebook.com/victim","twitter":"https://twitter.com/victim"}' (JSON format used by LP)
  3. Enroll in Course (Optional but recommended):
    • Create a dummy course: wp post create --post_type=lp_course --post_title="Secret Course" --post_status=publish
    • Get the course ID from the output.
    • Enroll the victim: wp eval "learn_press_get_user(2)->enroll(COURSE_ID);"

7. Expected Results

  • Success: The HTTP response code is 200 OK and the body contains the "Sensitive Information" strings and the social link URLs assigned in the setup phase.
  • Failure: The HTTP response code is 401 Unauthorized or 403 Forbidden, indicating the permission_callback is correctly blocking the request.

8. Verification Steps

  1. Post-Exploit Check: Compare the JSON response values with the database values.
    wp user get 2 --fields=display_name,user_email
    wp user meta get 2 first_name
    wp user meta get 2 last_name
  2. Confirm Unauthenticated: Ensure no Cookie or Authorization headers were sent in the http_request call.

9. Alternative Approaches

If /lp/v1/users/<id> is not the correct path, use the following commands to find the registered LearnPress routes:

  • wp eval "print_r(array_keys(rest_get_server()->get_routes()));" | grep lp/v1
  • Look specifically for routes containing (?P<id>[\d]+) or (?P<user_id>[\d]+).
  • If the target is the profile endpoint, try: /wp-json/lp/v1/profile/2.
  • Check if the endpoint requires a different ID format (e.g., username).
  • Check if the vulnerability exists in a search endpoint: /wp-json/lp/v1/users?search=victim.
Research Findings
Static analysis — not yet PoC-verified

Summary

The LearnPress plugin for WordPress fails to properly authorize requests to its user-related REST API endpoints. This allows unauthenticated attackers to retrieve sensitive user information, including first and last names, social profile links, and course enrollment details, by querying the API with a target user's ID.

Vulnerable Code

// File: inc/rest-api/v1/frontend/class-lp-rest-users-controller.php

public function get_item_permissions_check( $request ) {
    return true;
}

Security Fix

--- a/inc/rest-api/v1/frontend/class-lp-rest-users-controller.php
+++ b/inc/rest-api/v1/frontend/class-lp-rest-users-controller.php
@@ -100,5 +100,8 @@
 	public function get_item_permissions_check( $request ) {
-		return true;
+		if ( ! is_user_logged_in() ) {
+			return new WP_Error( 'rest_forbidden', __( 'Sorry, you are not allowed to access this resource.', 'learnpress' ), array( 'status' => 403 ) );
+		}
+
+		return true;
 	}

Exploit Outline

The exploit targets the LearnPress REST API by sending an unauthenticated GET request to /wp-json/lp/v1/users/<user_id> (where <user_id> is the ID of the target user). Since the get_item_permissions_check method incorrectly returns true for all requests, the API returns the full user profile data in JSON format, exposing personally identifiable information (PII) and enrollment history without any credentials.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.