CVE-2025-14783

Easy Digital Downloads <= 3.6.2 - Unvalidated Redirect in Password Reset Flow via edd_redirect

mediumWeak Password Recovery Mechanism for Forgotten Password
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
3.6.3
Patched in
1d
Time to patch

Description

The Easy Digital Downloads plugin for WordPress is vulnerable to Unvalidated Redirect in all versions up to, and including, 3.6.2. This is due to insufficient validation on the redirect url supplied via the 'edd_redirect' parameter. This makes it possible for unauthenticated attackers to redirect users with the password reset email to potentially malicious sites if they can successfully trick them into performing an action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.6.2
PublishedDecember 30, 2025
Last updatedDecember 31, 2025
Affected plugineasy-digital-downloads

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2025-14783 Unvalidated Redirect in Easy Digital Downloads ## 1. Vulnerability Summary Easy Digital Downloads (EDD) versions up to and including 3.6.2 are vulnerable to an unvalidated redirect. This occurs because the plugin accepts a user-supplied URL via the `edd_redirect` par…

Show full research plan

Research Plan: CVE-2025-14783 Unvalidated Redirect in Easy Digital Downloads

1. Vulnerability Summary

Easy Digital Downloads (EDD) versions up to and including 3.6.2 are vulnerable to an unvalidated redirect. This occurs because the plugin accepts a user-supplied URL via the edd_redirect parameter during the password reset flow and passes it directly to a redirection function (likely wp_redirect) without verifying if the domain is local or safe. An attacker can use this to craft a password reset link that, once used by a victim, redirects them to an external, potentially malicious site.

2. Attack Vector Analysis

  • Endpoint: The password reset processing handler. In EDD, this is typically handled via an action hook like template_redirect or a specific AJAX/POST handler for form submissions.
  • Parameter: edd_redirect.
  • Authentication: Unauthenticated (Password reset flows are accessible to any user who knows a username/email).
  • Preconditions: The site must have the EDD password reset functionality active, typically via the [edd_password_reset] shortcode.

3. Code Flow (Inferred)

Based on common EDD patterns and the vulnerability description:

  1. Entry Point: A user submits the password reset form or clicks a reset link.
  2. Processing: EDD's form processing logic (likely in includes/user-functions.php or includes/process-forms.php) triggers.
  3. Redirection Logic:
    • The code checks for the presence of $_REQUEST['edd_redirect'] or $_POST['edd_redirect'].
    • The plugin likely uses wp_redirect( $redirect_url ) instead of the more secure wp_safe_redirect().
  4. Sink: The Location header is set to the unvalidated external URL.

4. Nonce Acquisition Strategy

EDD usually protects its forms with nonces. To exploit this via a form submission, we must first obtain a valid nonce from the password reset page.

  1. Identify Shortcode: The standard EDD password reset shortcode is [edd_password_reset].
  2. Setup Test Page:
    wp post create --post_type=page --post_title="Reset Password" --post_status=publish --post_content='[edd_password_reset]'
    
  3. Navigate and Extract:
    • Navigate to the newly created page (e.g., /reset-password/).
    • EDD often localizes its scripts. Check for a global object like edd_scripts_vars or edd_vars.
    • Alternatively, inspect the HTML form for a hidden input field named edd_login_nonce or edd_password_nonce.
    • Browser Eval Command:
      // Check for common EDD nonce locations in the DOM
      document.querySelector('input[name="edd_password_nonce"]')?.value || 
      document.querySelector('input[name="_wpnonce"]')?.value
      

5. Exploitation Strategy

We will attempt to trigger the redirect by submitting a password reset request (or completing one) with the edd_redirect parameter set to an external domain.

Step 1: Discover the Processing Action

Search the codebase for the handler of edd_redirect in the context of password resets:

grep -rn "edd_redirect" /var/www/html/wp-content/plugins/easy-digital-downloads/ | grep "wp_redirect"

Step 2: Trigger Redirect via POST

Assuming the handler is triggered by a POST request to the password reset page:

HTTP Request:

  • Method: POST
  • URL: http://localhost:8080/reset-password/ (or the URL of the page containing the shortcode)
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    edd_action=reset_password&
    edd_user_login=admin&
    edd_redirect=https://evil.com&
    edd_password_nonce=[NONCE_FROM_STEP_4]
    

Step 3: Trigger Redirect via GET (Alternative)

Some redirect parameters in EDD are processed via template_redirect on GET requests.

HTTP Request:

  • Method: GET
  • URL: http://localhost:8080/reset-password/?edd_action=reset_password&edd_redirect=https://evil.com

6. Test Data Setup

  1. Install and activate Easy Digital Downloads.
  2. Create a standard subscriber user for testing the reset flow:
    wp user create victim victim@example.com --role=subscriber
    
  3. Create the reset page:
    wp post create --post_type=page --post_title="Password Reset" --post_status=publish --post_content='[edd_password_reset]'
    

7. Expected Results

  • The server should respond with a 302 Found status code.
  • The Location header in the response must be exactly https://evil.com.
  • If the vulnerability is present, wp_safe_redirect (which would normally prepend the site URL to an external path or default to home) will NOT have been used.

8. Verification Steps

After performing the HTTP request:

  1. Check Headers: Verify the Location header using the http_request output.
  2. Code Inspection (Post-Exploit): Confirm the fix in version 3.6.3:
    # Check if wp_safe_redirect is now used where edd_redirect was handled
    grep -rn "edd_redirect" /var/www/html/wp-content/plugins/easy-digital-downloads/
    

9. Alternative Approaches

If the simple POST/GET to the page doesn't work:

  1. Check edd_process_reset_password_form Action: Look for where this function is defined and see if it uses edd_redirect after sending the reset email.
  2. AJAX Handler: Check if EDD uses an AJAX action for the "Lost Password" request:
    • Action: edd_user_back_to_login or similar.
    • Search: grep -r "wp_ajax" . | grep "password"
  3. Password Reset Completion: The vulnerability might reside in the final step of the reset (where the user sets the new password). This would require a valid password reset key (edd_key and edd_login) generated by the system.
Research Findings
Static analysis — not yet PoC-verified

Summary

Easy Digital Downloads versions up to 3.6.2 are vulnerable to an unvalidated redirect in the password reset flow. The plugin accepts a user-controlled URL via the 'edd_redirect' parameter and uses it in a redirection call without proper validation, allowing attackers to redirect users to arbitrary external malicious sites.

Security Fix

--- a/includes/process-forms.php
+++ b/includes/process-forms.php
@@ -102,7 +102,7 @@
 	if ( ! empty( $_REQUEST['edd_redirect'] ) ) {
-		$redirect = $_REQUEST['edd_redirect'];
+		$redirect = wp_validate_redirect( $_REQUEST['edd_redirect'], edd_get_current_page_url() );
 	} else {
 		$redirect = edd_get_current_page_url();
 	}
 
-	wp_redirect( $redirect );
+	wp_safe_redirect( $redirect );
 	exit;

Exploit Outline

1. Identify the URL of the password reset page on the target site, which typically contains the '[edd_password_reset]' shortcode. 2. Access the page as an unauthenticated user and extract the value of the 'edd_password_nonce' hidden input field. 3. Construct a POST request to the same page (or the EDD processing handler) with the following parameters: 'edd_action' set to 'reset_password', 'edd_user_login' set to a valid username/email, 'edd_password_nonce' set to the extracted nonce, and 'edd_redirect' set to the target external URL (e.g., 'https://evil.com'). 4. Submit the request. If successful, the server will respond with a 302 Found status, and the 'Location' header will contain the attacker-supplied URL, demonstrating the unvalidated redirect.

Check if your site is affected.

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