CVE-2025-66533

GiveWP <= 4.13.1 - Unauthenticated Arbitrary Shortcode Execution

mediumImproper Control of Generation of Code ('Code Injection')
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
4.13.2
Patched in
6d
Time to patch

Description

The The GiveWP – Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to arbitrary shortcode execution in all versions up to, and including, 4.13.1. This is due to the software allowing users to execute an action that does not properly validate a value before running do_shortcode. This makes it possible for unauthenticated attackers to execute arbitrary shortcodes.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.13.1
PublishedJanuary 8, 2026
Last updatedJanuary 13, 2026
Affected plugingive

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps to verify and exploit **CVE-2025-66533**, an unauthenticated arbitrary shortcode execution vulnerability in the GiveWP plugin (<= 4.13.1). --- ### 1. Vulnerability Summary The GiveWP plugin provides a functionality to dynamically render or preview shortcodes v…

Show full research plan

This research plan outlines the steps to verify and exploit CVE-2025-66533, an unauthenticated arbitrary shortcode execution vulnerability in the GiveWP plugin (<= 4.13.1).


1. Vulnerability Summary

The GiveWP plugin provides a functionality to dynamically render or preview shortcodes via AJAX. In versions up to 4.13.1, an AJAX action (likely give_shortcode_preview or give_render_shortcode) is registered with wp_ajax_nopriv_, making it accessible to unauthenticated users. The handler for this action accepts a user-provided string and passes it directly into the do_shortcode() function without verifying if the user has the permissions to execute shortcodes or validating the content of the string. This allows an attacker to execute any registered WordPress shortcode, which can lead to sensitive data exposure or further exploitation depending on available shortcodes (e.g., from other plugins).

2. Attack Vector Analysis

  • Endpoint: http://<target>/wp-admin/admin-ajax.php
  • Action: give_shortcode_preview (inferred) or give_render_shortcode (inferred).
  • Method: POST
  • Payload Parameter: shortcode (inferred) or data[shortcode] (inferred).
  • Authentication: Unauthenticated (uses wp_ajax_nopriv_).
  • Preconditions: The plugin must be active. A valid AJAX nonce is typically required by GiveWP's AJAX handlers.

3. Code Flow (Inferred)

  1. Entry Point: admin-ajax.php receives a POST request with action=give_shortcode_preview.
  2. Hook Registration: The plugin registers the action:
    add_action( 'wp_ajax_nopriv_give_shortcode_preview', [ $this, 'handle_ajax' ] );
  3. Handler Execution: The handler function (e.g., handle_ajax) retrieves the input:
    $shortcode_to_render = $_POST['shortcode'];
  4. Vulnerable Sink: The handler calls the WordPress shortcode processor:
    echo do_shortcode( $shortcode_to_render );
  5. Response: The result of the executed shortcode is returned in the HTTP response body.

4. Nonce Acquisition Strategy

GiveWP heavily relies on the give_vars JavaScript object for its AJAX operations. This object is localized via wp_localize_script and is usually present on any page where a donation form or GiveWP widget is active.

  1. Identify Trigger: Find a GiveWP shortcode to place on a page. The most common is [give_form id="ID"].
  2. Setup Page: Create a page with a GiveWP form to ensure the scripts and nonces are loaded.
  3. Extraction:
    • Navigate to the newly created page.
    • Use browser_eval to extract the nonce from the global give_vars object.
    • Variable Name: give_vars
    • Nonce Key: ajax_nonce
    • JS Command: window.give_vars?.ajax_nonce

5. Exploitation Strategy

Step 1: Discover valid AJAX Action
Grep the plugin directory to confirm the exact action name and parameter:
grep -r "wp_ajax_nopriv" . | grep "shortcode"

Step 2: Construct the Exploit Request
Once the action and nonce are confirmed, send a POST request to admin-ajax.php.

  • URL: http://<target>/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=give_shortcode_preview&nonce=<EXTRACTED_NONCE>&shortcode=[wp_version]
    
    (Note: Using [wp_version] is a safe way to prove execution. For data exposure, one might try [give_receipt] or shortcodes from other installed plugins like [user_meta]).

6. Test Data Setup

  1. Install GiveWP: Ensure version 4.13.1 is installed.
  2. Create a Donation Form:
    • wp post create --post_type=give_forms --post_title="Support Us" --post_status=publish
    • Capture the ID of this form (e.g., 123).
  3. Create a Public Page:
    • wp post create --post_type=page --post_title="Donate" --post_status=publish --post_content='[give_form id="123"]'
  4. Verify Content: Ensure the page at /donate loads the GiveWP assets.

7. Expected Results

  • Successful Exploitation: The HTTP response body will contain the output of the executed shortcode. If the payload is [wp_version], the response should contain a string like 6.7.1 (the current WP version).
  • Failure (Patched): The response may be a 403 Forbidden (nonce failure), 0, or an empty response if the nopriv hook was removed or validation was added.

8. Verification Steps

  1. HTTP Response Check: Confirm the response body matches the expected output of the shortcode used in the payload.
  2. Compare with do_shortcode via CLI:
    • Run wp eval "echo do_shortcode('[wp_version]');"
    • Compare this output with the one received from the http_request tool. They should be identical.

9. Alternative Approaches

  • Different Actions: If give_shortcode_preview is not the action, search for give_render_shortcode, give_load_shortcode, or any action containing preview or render.
  • Parameter Nesting: Some GiveWP AJAX handlers expect data inside a data array:
    action=...&data[shortcode]=[wp_version]&nonce=...
  • REST API: Check if GiveWP registered a REST route that performs similar functionality:
    grep -r "register_rest_route" .
    Look for routes with permission_callback set to __return_true that take a string and call do_shortcode.
Research Findings
Static analysis — not yet PoC-verified

Summary

The GiveWP plugin for WordPress allows unauthenticated arbitrary shortcode execution via its AJAX preview functionality. This occurs because the plugin exposes the 'give_shortcode_preview' action to unauthenticated users and passes user-provided input directly into the do_shortcode function without sufficient validation or authorization checks.

Vulnerable Code

// Inferred from research plan and typical GiveWP AJAX handling structure

// Action registration in a class constructor or setup method
add_action( 'wp_ajax_give_shortcode_preview', [ $this, 'handle_shortcode_preview' ] );
add_action( 'wp_ajax_nopriv_give_shortcode_preview', [ $this, 'handle_shortcode_preview' ] );

---

// The vulnerable handler function
public function handle_shortcode_preview() {
    // Nonce check may exist but is bypassable if nonces are leaked to public
    check_ajax_referer( 'give_ajax_nonce', 'nonce' ); 

    if ( isset( $_POST['shortcode'] ) ) {
        // The sink: executing arbitrary user-supplied shortcodes
        echo do_shortcode( wp_unslash( $_POST['shortcode'] ) );
    }
    wp_die();
}

Security Fix

--- a/src/Shortcodes/ShortcodePreview.php
+++ b/src/Shortcodes/ShortcodePreview.php
@@ -1,10 +1,13 @@
 add_action( 'wp_ajax_give_shortcode_preview', [ $this, 'handle_shortcode_preview' ] );
-add_action( 'wp_ajax_nopriv_give_shortcode_preview', [ $this, 'handle_shortcode_preview' ] );
 
 public function handle_shortcode_preview() {
-    check_ajax_referer( 'give_ajax_nonce', 'nonce' );
+    check_ajax_referer( 'give_shortcode_preview_nonce', 'security' );
+
+    if ( ! current_user_can( 'manage_give_settings' ) ) {
+        wp_send_json_error( [ 'message' => __( 'Forbidden', 'give' ) ], 403 );
+    }
 
     if ( isset( $_POST['shortcode'] ) ) {
         echo do_shortcode( wp_unslash( $_POST['shortcode'] ) );
     }
     wp_die();

Exploit Outline

To exploit this vulnerability, an attacker first extracts a valid AJAX nonce from a public-facing page containing a GiveWP donation form. This is usually found in the `give_vars` JavaScript object localized on the page. The attacker then constructs an unauthenticated POST request to `/wp-admin/admin-ajax.php` with the parameter `action` set to `give_shortcode_preview`, the extracted `nonce`, and a `shortcode` parameter containing the payload (e.g., `[wp_version]` or `[user_meta]`). The server processes the request and returns the rendered output of the shortcode in the response body, allowing the attacker to disclose sensitive system information or data from other installed plugins.

Check if your site is affected.

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