CVE-2026-14250

Themehunk Login Registration <= 1.0.2 - Unauthenticated Privilege Escalation via 'role' Parameter

mediumImproper Privilege Management
6.3
CVSS Score
6.3
CVSS Score
medium
Severity
1.0.3
Patched in
1d
Time to patch

Description

The Themehunk Login Registration plugin for WordPress is vulnerable to privilege escalation in versions up to, and including, 1.0.2. This is due to the handle_frontend_register() function in the unauthenticated /thlogin/v1/register REST endpoint accepting a user-controlled 'role' parameter and validating it only against get_editable_roles() — which returns every defined editable site role, including 'editor' — before passing it to wp_insert_user(). This makes it possible for unauthenticated attackers, when public user registration is enabled, to create new accounts with the editor role.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.2
PublishedJuly 7, 2026
Last updatedJuly 8, 2026

What Changed in the Fix

Changes introduced in v1.0.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-14250 (Themehunk Login Registration Privilege Escalation) ## 1. Vulnerability Summary **CVE-2026-14250** is an improper privilege management vulnerability in the **Themehunk Login Registration** plugin (versions <= 1.0.2). The vulnerability exists in the unaut…

Show full research plan

Exploitation Research Plan: CVE-2026-14250 (Themehunk Login Registration Privilege Escalation)

1. Vulnerability Summary

CVE-2026-14250 is an improper privilege management vulnerability in the Themehunk Login Registration plugin (versions <= 1.0.2). The vulnerability exists in the unauthenticated REST API endpoint /thlogin/v1/register. The function handle_frontend_register() accepts a user-provided role parameter. Instead of restricting registration to a safe default (like subscriber), the plugin validates the requested role against get_editable_roles(). In the context of the plugin's execution, this check includes elevated roles like editor, allowing unauthenticated users to register with higher privileges.

2. Attack Vector Analysis

  • Endpoint: POST /wp-json/thlogin/v1/register
  • Authentication: Unauthenticated (requires users_can_register to be enabled in WordPress settings).
  • Vulnerable Parameter: role
  • Preconditions:
    • The WordPress setting "Anyone can register" must be enabled.
    • A valid REST API nonce (wp_rest) must be provided in the X-WP-Nonce header.

3. Code Flow

  1. Entry Point: A POST request is sent to the REST namespace thlogin/v1 at the /register route.
  2. Permission Check: The permission_callback calls check_registration_allowed(). This function typically verifies that the user is not already logged in and that site registration is open.
  3. Handler Execution: The request reaches THLogin_REST_API::handle_frontend_register().
  4. Parameter Extraction: The function extracts username, email, password, and role from the request body.
  5. Vulnerable Validation: The code retrieves a list of roles via get_editable_roles(). It checks if the user-supplied role exists in this array. Because this function returns all editable roles (including editor), the validation passes.
  6. Sink: The validated role and user details are passed to wp_insert_user(), creating the account with the specified role.

4. Nonce Acquisition Strategy

The endpoint requires a standard WordPress REST API nonce. The plugin enqueues scripts that expose this nonce on any page where the login/registration forms are present.

  1. Shortcode Identification: The plugin uses several shortcodes defined in includes/class-thlogin-frontend.php:
    • [thlogin_register_form]
    • [thlogin_form]
    • [thlogin_combined_form]
  2. Page Creation: Use WP-CLI to create a public page containing the registration shortcode to ensure the script is enqueued.
    wp post create --post_type=page --post_status=publish --post_title="Register" --post_content='[thlogin_register_form]'
    
  3. Extraction: Navigate to the newly created page and extract the nonce from the localized JavaScript object thLoginFrontendData.
    • Variable: window.thLoginFrontendData
    • Key: nonce
    • Tool Command: browser_eval("window.thLoginFrontendData?.nonce")

5. Exploitation Strategy

Step 1: Obtain REST Nonce

Navigate to the page with the shortcode and extract the nonce using the strategy above.

Step 2: Send Registration Request

Construct a POST request to the registration endpoint.

  • URL: http://<target>/wp-json/thlogin/v1/register
  • Method: POST
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: <EXTRACTED_NONCE>
  • Payload:
    {
      "username": "attacker_editor",
      "email": "attacker@example.com",
      "password": "Password123!",
      "role": "editor"
    }
    

Step 3: Expected Response

A successful registration should return a 200 OK or 201 Created status code with a JSON body indicating success (e.g., {"success": true, ...}).

6. Test Data Setup

  1. Enable Registration:
    wp option update users_can_register 1
    
  2. Install Plugin: Ensure Themehunk Login Registration version 1.0.2 is active.
  3. Create Trigger Page:
    wp post create --post_type=page --post_status=publish --post_title="Gate" --post_content='[thlogin_register_form]'
    

7. Expected Results

  • The REST API accepts the editor role without error.
  • A new user is created in the database with the editor role instead of the default subscriber role.

8. Verification Steps

After sending the HTTP request, verify the user's role via WP-CLI:

wp user get attacker_editor --field=roles

Success Criteria: The command returns editor.

9. Alternative Approaches

If the role parameter is not accepted as a top-level JSON key, it may be nested within a settings or user_data object (though the CVE description suggests a direct parameter). Check the args handling in handle_frontend_register if the primary payload fails.

If get_editable_roles() behavior differs across environments, try escalating to author or contributor to confirm the parameter is indeed being processed and validated against the role list.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Themehunk Login Registration plugin (<= 1.0.2) is vulnerable to unauthenticated privilege escalation via its registration REST API endpoint. An attacker can create a new account with elevated privileges, such as 'editor', by supplying a 'role' parameter that the plugin validates against all editable site roles instead of enforcing a restricted default.

Vulnerable Code

// includes/class-thlogin-rest-api.php lines 782-789
		$role = sanitize_text_field( $request->get_param( 'role' ) );
		if ( ! function_exists( 'get_editable_roles' ) ) {
			require_once ABSPATH . 'wp-admin/includes/user.php';
		}
		$default_role    = $general_settings['default_register_role'] ?? 'subscriber';
		$editable_roles  = array_keys( get_editable_roles() );
		$user_data['role'] = ( $role && in_array( $role, $editable_roles, true ) ) ? $role : $default_role;

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/themehunk-login-registration/1.0.2/includes/class-thlogin-rest-api.php	2025-10-08 11:39:48.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/themehunk-login-registration/1.0.3/includes/class-thlogin-rest-api.php	2026-07-01 12:53:12.000000000 +0000
@@ -779,13 +785,16 @@
 			'user_email' => $email,
 		];
 
-		$role = sanitize_text_field( $request->get_param( 'role' ) );
+		// Security: the role must NEVER be taken from the request. Allowing a
+		// client-supplied "role" parameter would let an unauthenticated visitor
+		// register as an Administrator (privilege escalation). Only the
+		// admin-configured default role is honored here.
 		if ( ! function_exists( 'get_editable_roles' ) ) {
 			require_once ABSPATH . 'wp-admin/includes/user.php';
 		}
-		$default_role    = $general_settings['default_register_role'] ?? 'subscriber';
-		$editable_roles  = array_keys( get_editable_roles() );
-		$user_data['role'] = ( $role && in_array( $role, $editable_roles, true ) ) ? $role : $default_role;
+		$default_role       = sanitize_text_field( $general_settings['default_register_role'] ?? 'subscriber' );
+		$editable_roles     = array_keys( get_editable_roles() );
+		$user_data['role']  = in_array( $default_role, $editable_roles, true ) ? $default_role : 'subscriber';

Exploit Outline

The exploit targets the `/wp-json/thlogin/v1/register` REST endpoint. An attacker first retrieves a valid `wp_rest` nonce from the `thLoginFrontendData` JavaScript object on any page where the plugin's registration shortcode is rendered. Using this nonce, the attacker sends an unauthenticated POST request to the registration endpoint with a JSON payload containing the desired username, email, and password. Crucially, the attacker includes a 'role' parameter set to 'editor'. Because the vulnerable code uses `get_editable_roles()` to validate the input, and that function includes high-level roles when processed during account creation, the plugin allows the registration to proceed with the elevated role.

Check if your site is affected.

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