LearnPress – WordPress LMS Plugin <= 4.3.2.4 - Missing Authorization to Unauthenticated Sensitive User Information Disclosure via REST API
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:NTechnical Details
<=4.3.2.4Source Code
WordPress.org SVN# 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
idpath 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
- Route Registration: The plugin registers REST routes in
inc/rest-api/v1/frontend/class-lp-rest-users-controller.php(or similar) usingregister_rest_route. - Permission Callback: The route for fetching a user item (
GET) is configured with a'permission_callback' => array( $this, 'get_item_permissions_check' ). - The Vulnerability: Inside
get_item_permissions_check($request), the code returnstruewithout checkingis_user_logged_in()or verifying if the requester has theedit_userscapability or if they are requesting their own data. - 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 likefirst_name,last_name,social_links, andenrolled_courses. - 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:
- Identify Script Loading: LearnPress typically enqueues its localized scripts on its profile page. The shortcode
[learn_press_profile]is the primary trigger. - Setup: Create a "Profile" page:
wp post create --post_type=page --post_title="LP Profile" --post_status=publish --post_content='[learn_press_profile]' - Acquisition:
- Navigate to the new page.
- Use
browser_evalto extract the LearnPress settings object:browser_eval("window.lpGlobalSettings?.nonce")orbrowser_eval("window.lpData?.nonce"). - Verbatim check: Search
lp-main.jsor the page source forlpGlobalSettingsorlearn_press_js_localize.
5. Exploitation Strategy
- Target Identification: We will attempt to disclose information for User ID 2 (usually the first user created after the admin).
- Request: Perform an unauthenticated GET request to the LearnPress User REST endpoint.
- 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: 2first_name: "..."last_name: "..."social_links: { ... }enrolled_courses: [ ... ]
6. Test Data Setup
- Create Victim User:
wp user create victim victim@example.com --role=subscriber --user_pass=password123 - 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) - 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);"
- Create a dummy course:
7. Expected Results
- Success: The HTTP response code is
200 OKand the body contains the "Sensitive Information" strings and the social link URLs assigned in the setup phase. - Failure: The HTTP response code is
401 Unauthorizedor403 Forbidden, indicating thepermission_callbackis correctly blocking the request.
8. Verification Steps
- Post-Exploit Check: Compare the JSON response values with the database values.
wp user get 2 --fields=display_name,user_emailwp user meta get 2 first_namewp user meta get 2 last_name - Confirm Unauthenticated: Ensure no
CookieorAuthorizationheaders were sent in thehttp_requestcall.
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.
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
@@ -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.