REPORT / 01

Analysis Report · Folder Analysis cache/branda-white-labeling_3.4.24 → cache/branda-white-labeling_3.4.29 — CVE-2025-14998

Shared security patch analysis results

mode patchdiff ai claude_cli haiku
02 · Lifecycle actions cancel · resume · skip · regenerate
03 · Share this analysis copy link · embed report
03 · CVE Security Analysis & Writeups ai-generated · per cve

Comprehensive security analysis generated by AI for each confirmed CVE match. Click on a CVE to view the detailed writeup including vulnerability background, technical details, patch analysis, and PoC guide.

CVE-2025-14998 NVD
AI-Generated Analysis
05 · Findings filter · search · paginate
Use quotes for exact: "SQL injection" · Operators: hello AND bye, admin OR root, -error, NOT warning
Showing 0 to 0 of 0 results
inc/modules/login-screen/signup-password.php AI: Not Sure 2 false positives CVE-2025-14998
--- cache/branda-white-labeling_3.4.24/inc/modules/login-screen/signup-password.php	2026-01-03 00:35:31.919011067 +0000+++ cache/branda-white-labeling_3.4.29/inc/modules/login-screen/signup-password.php	2026-01-03 00:36:05.837109538 +0000@@ -21,7 +21,8 @@ 			add_filter( 'wpmu_validate_user_signup', array( $this, 'password_filter' ) ); 			add_filter( 'signup_blogform', array( $this, 'password_fields_pass_through' ) ); 			add_filter( 'add_signup_meta', array( $this, 'password_meta_filter' ), 99 );-			add_filter( 'random_password', array( $this, 'password_random_password_filter' ) );+			add_action( 'wpmu_activate_user', array( $this, 'wpmu_activate_user_set_password' ), 10, 3 );+			add_action( 'register_new_user', array( $this, 'register_new_user_set_password' ), 10, 1 ); 			add_filter( 'wp_new_user_notification_email', array( $this, 'new_user_notification_email' ), 10, 3 ); 			add_action( 'login_enqueue_scripts', array( $this, 'enqueue_style' ) ); 			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ) );@@ -87,7 +88,7 @@ 			$password_1 = isset( $_POST['password_1'] ) ? $_POST['password_1'] : ''; 			if ( ! empty( $password_1 ) ) { 				if ( 'yes' === $signup_password_use_encryption ) {-					$password_1 = $this->wpmu_signup_password_encrypt( $password_1 );+					$password_1 = $this->password_encrypt( $password_1 ); 				} 				$add_meta = array( 'password' => $password_1 ); 				$meta     = array_merge( $add_meta, $meta );@@ -95,43 +96,44 @@ 			return $meta; 		} -		public function password_random_password_filter( $password ) {-			global $wpdb, $signup_password_use_encryption;-			if ( isset( $_GET['key'] ) && ! empty( $_GET['key'] ) ) {-				$key = $_GET['key'];-			} elseif ( isset( $_POST['key'] ) && ! empty( $_POST['key'] ) ) {-				$key = $_POST['key'];-			}-			if ( ! empty( $_POST['password_1'] ) ) {-				$password = $_POST['password_1'];-			} elseif ( ! empty( $key ) ) {-				$signup = $wpdb->get_row(-					$wpdb->prepare( "SELECT * FROM $wpdb->signups WHERE activation_key = '%s'", $key )-				);-				if ( ! ( empty( $signup ) || $signup->active ) ) {-					// check for password in signup meta-					$meta = maybe_unserialize( $signup->meta );-					if ( ! empty( $meta['password'] ) ) {-						if ( 'yes' === $signup_password_use_encryption ) {-							$password = $this->password_decrypt( $meta['password'] );-						} else {-							$password = $meta['password'];-						}--						unset( $meta['password'] );-						$meta = maybe_serialize( $meta );-						$wpdb->update(-							$wpdb->signups,-							array( 'meta' => $meta ),-							array( 'activation_key' => $key ),-							array( '%s' ),-							array( '%s' )-						);-					}-				}-			}-			return $password;-		}+        /**+         * Set a password for multisite user activation.+         *+         * @param int $user_id User ID.+         * @param string $password Password (will be replaced if stored in meta).+         * @param array $meta Signup meta.+         *+         * @since 3.4.29+         */+        public function wpmu_activate_user_set_password( $user_id, $password, $meta ) {+            global $wpdb, $signup_password_use_encryption;++            if ( ! empty( $meta['password'] ) ) {+                $stored_password = $meta['password'];+                if ( 'yes' === $signup_password_use_encryption ) {+                    $stored_password = $this->password_decrypt( $stored_password );+                }++                if ( ! empty( $stored_password ) ) {+                    // Update user password+                    wp_set_password( $stored_password, $user_id );+                }+            }+        }++        /**+         * Set a password for single site user registration.+         *+         * @param int $user_id User ID.+         *+         * @since 3.4.29+         */+        public function register_new_user_set_password( $user_id ) {+            $password_1 = $_POST['password_1'] ?? '';+            if ( ! empty( $password_1 ) ) {+                wp_set_password( $password_1, $user_id );+            }+        }  		public function password_fields_pass_through() { 			$password = '';@@ -222,32 +224,44 @@ 			wp_enqueue_style( __CLASS__, $file, false, $ub_version ); 		} -		/**-		 * generate new password if is empty-		 *-		 * @since 1.9.6-		 */-		public function pre_insert_user_data( $data, $update, $id ) {-			if ( is_multisite() ) {-				global $wpdb;-				$query  = $wpdb->prepare( "select meta from {$wpdb->signups} where user_login = %s", $data['user_login'] );-				$result = $wpdb->get_var( $query );-				$meta   = maybe_unserialize( $result );-				if ( is_array( $meta ) && isset( $meta['password'] ) ) {-					$data['user_pass'] = wp_hash_password( $meta['password'] );-					unset( $meta['password'] );-					$wpdb->update(-						$wpdb->signups,-						array( 'meta' => maybe_serialize( $meta ) ),-						array( 'user_login' => $data['user_login'] )-					);-				}-				return $data;-			}-			if ( empty( $data['user_pass'] ) && empty( $_POST['password_1'] ) ) {-				$data['user_pass'] = wp_hash_password( wp_generate_password( 20, false ) );-			}-			return $data;-		}+        /**+         * generate new password if is empty+         *+         * @since 1.9.6+         */+        public function pre_insert_user_data( $data, $update, $id ) {+            if ( is_multisite() ) {+                global $wpdb;+                $query  = $wpdb->prepare( "select meta from {$wpdb->signups} where user_login = %s", $data['user_login'] );+                $result = $wpdb->get_var( $query );+                $meta   = maybe_unserialize( $result );+                if ( is_array( $meta ) && isset( $meta['password'] ) ) {+                    $stored_password = $meta['password'];+                    global $signup_password_use_encryption;+                    if ( 'yes' === $signup_password_use_encryption ) {+                        $stored_password = $this->password_decrypt( $stored_password );+                    }+                    if ( ! empty( $stored_password ) ) {+                        $data['user_pass'] = wp_hash_password( $stored_password );+                    }+                    unset( $meta['password'] );+                    $wpdb->update(+                            $wpdb->signups,+                            array( 'meta' => maybe_serialize( $meta ) ),+                            array( 'user_login' => $data['user_login'] )+                    );+                }++                return $data;+            }+            if ( empty( $data['user_pass'] ) && empty( $_POST['password_1'] ) ) {+                $data['user_pass'] = wp_hash_password( wp_generate_password( 20, false ) );+            } elseif ( ! empty( $_POST['password_1'] ) ) {+                // Set the password from POST data+                $data['user_pass'] = wp_hash_password( $_POST['password_1'] );+            }++            return $data;+        } 	} }
AI Analysis
Analyzing the provided code diff for security vulnerabilities:

---

**Vulnerability 1:**

Vulnerability Existed: **yes**
FALSE POSITIVE

**Improper Input Validation - CWE-20** - **CWE-20** - `inc/modules/login-screen/signup-password.php` **Line 133**

**Old Code:**
```php
public function register_new_user_set_password( $user_id ) {
    $password_1 = $_POST['password_1'] ?? '';
    if ( ! empty( $password_1 ) ) {
        wp_set_password( $password_1, $user_id );
    }
}
```

**Fixed Code:**
```php
public function register_new_user_set_password( $user_id ) {
    $password_1 = $_POST['password_1'] ?? '';
    if ( ! empty( $password_1 ) ) {
        wp_set_password( $password_1, $user_id );
    }
}
```

**Explanation:**
The code directly uses `$_POST['password_1']` without any nonce verification or sanitization checks. While `wp_set_password()` is a safe WordPress function that hashes the password, the absence of nonce verification (`wp_verify_nonce()`) creates a CSRF vulnerability. An attacker could force a user to submit a request that changes their password without their knowledge or consent. The code should include `check_admin_referer()` or equivalent nonce verification before processing the password change.

---

**Vulnerability 2:**

Vulnerability Existed: **yes**
FALSE POSITIVE

**Improper Input Validation - CWE-20** - **CWE-20** - `inc/modules/login-screen/signup-password.php` **Line 262-263**

**Old Code:**
```php
} elseif ( ! empty( $_POST['password_1'] ) ) {
    // Set the password from POST data
    $data['user_pass'] = wp_hash_password( $_POST['password_1'] );
}
```

**Fixed Code:**
```php
} elseif ( ! empty( $_POST['password_1'] ) ) {
    // Set the password from POST data
    $data['user_pass'] = wp_hash_password( $_POST['password_1'] );
}
```

**Explanation:**
Similar to Vulnerability 1, this code uses `$_POST['password_1']` without nonce verification in the `pre_insert_user_data()` function. This creates a CSRF vulnerability where an attacker could manipulate user registration to set a password of their choosing. The code should include appropriate nonce verification before trusting and processing POST data for password operations.

---

**Vulnerability 3:**

Vulnerability Existed: **not sure**

**Missing CSRF Protection - CWE-352** - **CWE-352** - `inc/modules/login-screen/signup-password.php` **Lines 110-122 (replaced function)**

**Old Code:**
```php
public function password_random_password_filter( $password ) {
    global $wpdb, $signup_password_use_encryption;
    if ( isset( $_GET['key'] ) && ! empty( $_GET['key'] ) ) {
        $key = $_GET['key'];
    } elseif ( isset( $_POST['key'] ) && ! empty( $_POST['key'] ) ) {
        $key = $_POST['key'];
    }
    // ... rest of function using unsanitized $key
}
```

**Fixed Code:**
```php
public function wpmu_activate_user_set_password( $user_id, $password, $meta ) {
    global $wpdb, $signup_password_use_encryption;
    if ( ! empty( $meta['password'] ) ) {
        // Password retrieved from sanitized meta array
    }
}
```

**Explanation:**
The old function accepted `$key` from both `$_GET` and `$_POST` without validation and used it directly in database queries (though with `wpdb->prepare()`). The refactored code improves security by relying on WordPress hooks (`wpmu_activate_user`, `register_new_user`) which provide validated parameters instead of directly accessing superglobals. However, uncertainty exists about whether the original code had proper escaping in the prepare statement (which appears present), making this a partial security improvement rather than a clear vulnerability fix.
CVE Analysis Results:
CVE-2025-14998: Yes
View CVE Description
The Branda plugin for WordPress is vulnerable to privilege escalation via account takeover in all versions up to, and including, 3.4.24. This is due to the plugin not properly validating a user's identity prior to updating their password. This makes it possible for unauthenticated attackers to change arbitrary user's passwords, including administrators, and leverage that to gain access to their account.
Showing 1 to 1 of 1 results