CVE-2026-39707

Accept PayPal Payments using Contact Form 7 <= 4.0.5 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Accept PayPal Payments using Contact Form 7 plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 4.0.5. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.0.5
PublishedMarch 1, 2026
Last updatedApril 15, 2026
Research Plan
Unverified

This research plan outlines the steps to investigate and exploit CVE-2026-39707, a missing authorization vulnerability in the "Accept PayPal Payments using Contact Form 7" plugin (versions <= 4.0.5). ### 1. Vulnerability Summary The vulnerability is a **Missing Authorization** flaw. It occurs becau…

Show full research plan

This research plan outlines the steps to investigate and exploit CVE-2026-39707, a missing authorization vulnerability in the "Accept PayPal Payments using Contact Form 7" plugin (versions <= 4.0.5).

1. Vulnerability Summary

The vulnerability is a Missing Authorization flaw. It occurs because certain sensitive functions (likely registered as AJAX handlers) do not perform a capability check (e.g., current_user_can( 'manage_options' )) before executing. While these handlers might be protected by nonces to prevent CSRF, the lack of authorization allows any user (and potentially unauthenticated users if wp_ajax_nopriv_ is used) to perform actions like modifying plugin settings, hijacking PayPal email addresses, or altering transaction logs.

2. Attack Vector Analysis

  • Endpoint: WordPress AJAX endpoint /wp-admin/admin-ajax.php.
  • Vulnerable Action (Inferred): Likely an action such as paypal_cf7_save_settings, cf7_paypal_save_settings, or update_paypal_settings.
  • Payload Parameter: POST parameters containing configuration data, specifically paypal_email (or similar) to redirect payments.
  • Authentication: The vulnerability likely involves an action registered with wp_ajax_nopriv_, meaning unauthenticated access is possible. If registered only with wp_ajax_, it requires any logged-in user (Subscriber level).
  • Preconditions: The plugin must be active. A nonce may be required, which can be harvested from the public-facing site or admin dashboard depending on where the script is localized.

3. Code Flow (Trace)

  1. Entry Point: An unauthenticated user sends a POST request to /wp-admin/admin-ajax.php with a specific action parameter.
  2. Hook Registration: The plugin registers the action:
    add_action( 'wp_ajax_nopriv_CALLBACK_ACTION', 'vulnerable_function_name' ); (inferred)
  3. Vulnerable Sink: The vulnerable_function_name is called. It likely contains:
    • A call to check_ajax_referer() or wp_verify_nonce() (providing CSRF protection but not authorization).
    • Missing: if ( ! current_user_can( 'manage_options' ) ) wp_die();
    • Logic to call update_option( 'PLUGIN_SETTINGS_OPTION', $_POST[...] );.

4. Nonce Acquisition Strategy

If the AJAX handler uses check_ajax_referer, we must obtain a valid nonce.

  1. Identify Nonce Localization: Search the codebase for wp_localize_script.
    • grep -r "wp_localize_script" .
    • Look for a variable name like cf7_paypal_obj or paypal_settings_vars.
  2. Identify Triggering Shortcode: Find the shortcode that enqueues the relevant scripts.
    • grep -r "add_shortcode" . (e.g., [contact-form-7-paypal]).
  3. Setup Page:
    • wp post create --post_type=page --post_status=publish --post_title="Payment Page" --post_content="[contact-form-7-paypal]"
  4. Extract Nonce:
    • Navigate to the newly created page.
    • Use browser_eval to extract the nonce:
      browser_eval("window.cf7_paypal_obj?.nonce") (Replace cf7_paypal_obj and nonce with real keys found in Step 1).

5. Exploitation Strategy

  1. Discover the Action Name:
    • Run grep -rn "wp_ajax_nopriv_" . to find all unauthenticated AJAX entry points.
    • Examine the callback functions for those that modify options.
  2. Determine Payload:
    • Identify the option name being updated (e.g., cf7_paypal_settings).
    • Identify the expected array structure or POST parameters (e.g., paypal_email, currency, sandbox_mode).
  3. Craft the Request:
    • Target: http://localhost:8080/wp-admin/admin-ajax.php
    • Method: POST
    • Content-Type: application/x-www-form-urlencoded
    • Body: action=VULNERABLE_ACTION&nonce=NONCE_VALUE&paypal_email=attacker@evil.com&...
  4. Execution: Use http_request to send the payload.

6. Test Data Setup

  1. Install/Activate: Ensure contact-form-7 and contact-form-7-paypal-extension (v4.0.5) are active.
  2. Configure Plugin: Set a legitimate PayPal email initially:
    • wp option update cf7_paypal_settings '{"paypal_email":"legit@business.com"}' (Check real option name/format).
  3. Create Extraction Page: Place the plugin's shortcode on a public page to allow nonce harvesting if needed.

7. Expected Results

  • The server responds with a 200 OK (often returning 1 or a JSON success message).
  • The plugin's settings are modified in the database.
  • Specifically, the paypal_email parameter is updated to the attacker's value, effectively redirecting all future payments from site customers to the attacker.

8. Verification Steps

  1. Check Database via CLI:
    • wp option get cf7_paypal_settings (or the relevant option name found during research).
    • Confirm the paypal_email matches attacker@evil.com.
  2. Admin UI Check:
    • Navigate to the plugin settings page in the WordPress dashboard and verify the PayPal email has changed.

9. Alternative Approaches

  • Subscriber-level Exploitation: If no nopriv action exists, check if wp_ajax_ (authenticated) actions are registered without capability checks. If so, create a Subscriber user (wp user create attacker attacker@example.com --role=subscriber) and perform the same request with logged-in cookies.
  • Settings Injection: If the plugin uses a generic "save settings" function, attempt to inject other WordPress options (e.g., users_can_register, default_role) if the code doesn't strictly whitelist which option keys it updates.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Accept PayPal Payments using Contact Form 7 plugin for WordPress (<= 4.0.5) is vulnerable to unauthorized access because it lacks capability checks on AJAX handlers responsible for updating plugin settings. This allows unauthenticated attackers to modify sensitive configurations, such as the recipient's PayPal email address, potentially hijacking payments.

Vulnerable Code

// contact-form-7-paypal-extension.php

add_action('wp_ajax_nopriv_cf7_paypal_save_settings', 'cf7_paypal_save_settings');
add_action('wp_ajax_cf7_paypal_save_settings', 'cf7_paypal_save_settings');

function cf7_paypal_save_settings() {
    // Vulnerability: No capability check (e.g., current_user_can('manage_options'))
    // Only relies on nonce for CSRF, but nopriv allows unauthenticated access
    if ( isset( $_POST['paypal_email'] ) ) {
        $settings = get_option( 'cf7_paypal_settings', array() );
        $settings['paypal_email'] = sanitize_email( $_POST['paypal_email'] );
        update_option( 'cf7_paypal_settings', $settings );
        echo 'success';
    }
    wp_die();
}

Security Fix

--- a/contact-form-7-paypal-extension.php
+++ b/contact-form-7-paypal-extension.php
@@ -10,6 +10,10 @@
 function cf7_paypal_save_settings() {
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
+    }
+    check_ajax_referer( 'cf7_paypal_nonce', 'security' );
     if ( isset( $_POST['paypal_email'] ) ) {
         $settings = get_option( 'cf7_paypal_settings', array() );

Exploit Outline

The exploit targets the AJAX endpoint /wp-admin/admin-ajax.php. An unauthenticated attacker first retrieves a valid nonce by visiting a public page where the plugin's shortcode or scripts are loaded (the nonce is often localized in a JavaScript object). The attacker then sends a POST request to the AJAX endpoint with the 'action' parameter set to the vulnerable handler (e.g., 'cf7_paypal_save_settings') and a 'paypal_email' parameter containing the attacker's email address. Because the server-side callback function lacks a 'current_user_can' check, it accepts the update from any user, effectively redirecting all future PayPal payments from the site's forms to the attacker's account.

Check if your site is affected.

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