GiveWP <= 4.13.1 - Unauthenticated Arbitrary Shortcode Execution
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:NTechnical Details
Source Code
WordPress.org SVNThis 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) orgive_render_shortcode(inferred). - Method:
POST - Payload Parameter:
shortcode(inferred) ordata[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)
- Entry Point:
admin-ajax.phpreceives a POST request withaction=give_shortcode_preview. - Hook Registration: The plugin registers the action:
add_action( 'wp_ajax_nopriv_give_shortcode_preview', [ $this, 'handle_ajax' ] ); - Handler Execution: The handler function (e.g.,
handle_ajax) retrieves the input:$shortcode_to_render = $_POST['shortcode']; - Vulnerable Sink: The handler calls the WordPress shortcode processor:
echo do_shortcode( $shortcode_to_render ); - 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.
- Identify Trigger: Find a GiveWP shortcode to place on a page. The most common is
[give_form id="ID"]. - Setup Page: Create a page with a GiveWP form to ensure the scripts and nonces are loaded.
- Extraction:
- Navigate to the newly created page.
- Use
browser_evalto extract the nonce from the globalgive_varsobject. - 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:
(Note: Usingaction=give_shortcode_preview&nonce=<EXTRACTED_NONCE>&shortcode=[wp_version][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
- Install GiveWP: Ensure version 4.13.1 is installed.
- 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).
- Create a Public Page:
wp post create --post_type=page --post_title="Donate" --post_status=publish --post_content='[give_form id="123"]'
- Verify Content: Ensure the page at
/donateloads 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 like6.7.1(the current WP version). - Failure (Patched): The response may be a
403 Forbidden(nonce failure),0, or an empty response if thenoprivhook was removed or validation was added.
8. Verification Steps
- HTTP Response Check: Confirm the response body matches the expected output of the shortcode used in the payload.
- Compare with
do_shortcodevia CLI:- Run
wp eval "echo do_shortcode('[wp_version]');" - Compare this output with the one received from the
http_requesttool. They should be identical.
- Run
9. Alternative Approaches
- Different Actions: If
give_shortcode_previewis not the action, search forgive_render_shortcode,give_load_shortcode, or any action containingprevieworrender. - Parameter Nesting: Some GiveWP AJAX handlers expect data inside a
dataarray: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 withpermission_callbackset to__return_truethat take a string and calldo_shortcode.
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
@@ -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.