CVE-2026-32433

CP Contact Form with Paypal <= 1.3.61 - Authenticated (Contributor+) SQL Injection

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
1.3.62
Patched in
45d
Time to patch

Description

The CP Contact Form with Paypal plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.3.61 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with contributor-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.3.61
PublishedMarch 2, 2026
Last updatedApril 15, 2026

What Changed in the Fix

Changes introduced in v1.3.62

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This exploitation research plan targets an authenticated SQL injection vulnerability in the **CP Contact Form with PayPal** plugin (versions <= 1.3.61). The vulnerability arises from the plugin's data management logic, which processes user-supplied parameters in raw SQL queries without using `$wpdb-…

Show full research plan

This exploitation research plan targets an authenticated SQL injection vulnerability in the CP Contact Form with PayPal plugin (versions <= 1.3.61). The vulnerability arises from the plugin's data management logic, which processes user-supplied parameters in raw SQL queries without using $wpdb->prepare().

1. Vulnerability Summary

  • Vulnerability: Authenticated SQL Injection
  • Affected Parameter: ids (or uids) used in CSV export or message management.
  • Vulnerable Sink: cp_contactformpp_data_management_loaded() in cp_contactformpp_functions.php.
  • Reason: The plugin uses string concatenation to build a SELECT query with an IN clause using the user-supplied ids parameter. It fails to sanitize the input or use prepared statements, allowing an attacker to break out of the query.
  • Privilege Level: Contributor or higher. While the settings page is limited to manage_options, the data processing logic in wp_loaded often checks for the edit_posts capability, which Contributors possess.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/index.php or / (triggered via the wp_loaded hook).
  • Action: cp_contact_form_paypal_export_csv.
  • HTTP Parameter: ids (sent via GET or POST).
  • Authentication: Required (Contributor-level session).
  • Preconditions: At least one entry must exist in the cp_contact_form_paypal_posts table for the query to return results or for the time-based injection to be clearly observable.

3. Code Flow

  1. Entry Point: The plugin registers cp_contactformpp_data_management_loaded on the wp_loaded hook in cp_contactformpp.php.
    add_action('wp_loaded', 'cp_contactformpp_data_management_loaded' );
    
  2. Logic Dispatch: Inside cp_contactformpp_functions.php, the function cp_contactformpp_data_management_loaded() checks for the action parameter.
    function cp_contactformpp_data_management_loaded() {
        if (isset($_GET['action']) && $_GET['action'] == 'cp_contact_form_paypal_export_csv') {
            // Capability check (often edit_posts or missing)
            if (current_user_can('edit_posts')) {
                cp_contact_form_paypal_export_csv();
            }
        }
    }
    
  3. The Sink: The export function retrieves the ids parameter and concatenates it into a SQL query.
    function cp_contact_form_paypal_export_csv() {
        global $wpdb;
        $ids = $_GET['ids']; // SINK: Directly from $_GET
        $table = $wpdb->prefix . "cp_contact_form_paypal_posts";
        // Vulnerable Query
        $results = $wpdb->get_results("SELECT * FROM $table WHERE id IN ($ids)");
        // ... processes $results into CSV ...
    }
    

4. Nonce Acquisition Strategy

In many versions of this plugin, the wp_loaded actions for CSV export

Research Findings
Static analysis — not yet PoC-verified

Summary

The CP Contact Form with PayPal plugin is vulnerable to authenticated SQL Injection because it concatenates user-controlled variables like 'id' directly into SQL queries without using $wpdb->prepare() or integer casting. Attackers with Contributor-level access or higher can exploit this to extract sensitive database information via time-based or boolean-based blind injection techniques.

Vulnerable Code

// cp_contactformpp_functions.php line 310
if ($id != '')
    $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=".$id );

---

// cp_contactformpp_functions.php line 1509
else
{
   $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=".$id );
   if (count($myrows)) 
   {
       $value = $myrows[0]->$field;
       $cp_contactformpp_option_buffered_item = $myrows[0];
       $cp_contactformpp_option_buffered_id = $id;
   }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/cp-contact-form-with-paypal/1.3.61/cp_contactformpp_functions.php /home/deploy/wp-safety.org/data/plugin-versions/cp-contact-form-with-paypal/1.3.62/cp_contactformpp_functions.php
--- /home/deploy/wp-safety.org/data/plugin-versions/cp-contact-form-with-paypal/1.3.61/cp_contactformpp_functions.php	2026-02-05 11:47:06.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/cp-contact-form-with-paypal/1.3.62/cp_contactformpp_functions.php	2026-02-16 18:30:40.000000000 +0000
@@ -310,8 +310,8 @@
     $CP_CPP_global_form_count = "_".$CP_CFPP_global_form_count_number;  
     if (!defined('CP_AUTH_INCLUDE')) define('CP_AUTH_INCLUDE', true);
 
-    if ($id != '')
-        $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=".$id );
+    if ($id != '')        
+        $myrows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=%d", $id) );
     else
         $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE );
     if ($id == '') $id = $myrows[0]->id;
@@ -1503,12 +1508,13 @@
     }    
     if ($id == '') 
         $id = CP_CONTACTFORMPP_ID;
+    $id = intval($id);
     global $wpdb, $cp_contactformpp_option_buffered_item, $cp_contactformpp_option_buffered_id;
     if ($cp_contactformpp_option_buffered_id == $id)
         $value = (property_exists($cp_contactformpp_option_buffered_item, $field) && isset($cp_contactformpp_option_buffered_item->$field) ? @$cp_contactformpp_option_buffered_item->$field : '');
     else
     {
-       $myrows = $wpdb->get_results( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=".$id );
+       $myrows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM ".$wpdb->prefix.CP_CONTACTFORMPP_FORMS_TABLE." WHERE id=%d", $id) );
        if (count($myrows)) 
        {

Exploit Outline

The exploit targets endpoints that process the 'id' or 'ids' parameters, such as form settings retrieval or CSV data export. An authenticated user (Contributor or higher) sends a request (GET or POST) containing a malicious SQL payload in place of the expected integer ID. For example, setting 'id=1 OR SLEEP(5)' in a request that triggers form data retrieval allows an attacker to confirm the vulnerability via a time-based delay. Since the plugin fails to sanitize these inputs before appending them to the WHERE clause, standard SQL injection payloads can be used to exfiltrate data from the 'wp_users' table or other sensitive tables.

Check if your site is affected.

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