CVE-2026-9843

Database for Contact Form 7, WPforms, Elementor forms <= 1.5.1 - Unauthenticated Arbitrary File Deletion via CF7 File Field POST Value

highImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
8.1
CVSS Score
8.1
CVSS Score
high
Severity
1.5.2
Patched in
1d
Time to patch

Description

The Database for Contact Form 7, WPforms, Elementor forms plugin for WordPress is vulnerable to arbitrary file deletion due to insufficient file path validation in the view_page function in all versions up to, and including, 1.5.1. This makes it possible for unauthenticated attackers to delete arbitrary files on the server, which can easily lead to remote code execution when the right file is deleted (such as wp-config.php). Successful exploitation requires an administrator to view or edit the poisoned form entry, at which point PHP's bracket parser reshapes the attacker-crafted JSON key to bypass the stored-path isset check and trigger deletion of the traversal-specified file.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.5.1
PublishedJune 19, 2026
Last updatedJune 20, 2026
Affected plugincontact-form-entries

What Changed in the Fix

Changes introduced in v1.5.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on **CVE-2026-9843**, a path traversal vulnerability in the "Database for Contact Form 7" plugin that allows for arbitrary file deletion. ### 1. Vulnerability Summary The "Database for Contact Form 7, WPforms, Elementor forms" plugin (versions <= 1.5.1) fails to properly …

Show full research plan

This research plan focuses on CVE-2026-9843, a path traversal vulnerability in the "Database for Contact Form 7" plugin that allows for arbitrary file deletion.

1. Vulnerability Summary

The "Database for Contact Form 7, WPforms, Elementor forms" plugin (versions <= 1.5.1) fails to properly validate file paths stored in form entries. An unauthenticated attacker can submit a contact form with a specially crafted field name containing path traversal sequences (e.g., ../../../../wp-config.php).

When an administrator later views or edits this poisoned entry in the WordPress dashboard, the plugin's view_page functionality processes the entry data. Due to how PHP's bracket parser handles nested array keys in $_POST (reshaping them), an attacker can bypass isset() checks intended to verify that a file belongs to the entry. This allows the attacker to trigger the deletion (unlink) of any file the web server has permissions to delete.

2. Attack Vector Analysis

  • Target Endpoint: Public-facing contact forms (Contact Form 7, WPForms, or Elementor) integrated with the plugin.
  • Submission Endpoint (CF7 Example): /wp-json/contact-form-7/v1/contact-forms/<ID>/feedback
  • Trigger Endpoint (Admin): wp-admin/admin.php?page=vxcf_leads&action=edit&id=<Entry_ID>
  • Vulnerable Parameter: The key of a POST parameter intended for file uploads (e.g., vx_file[path/to/file]).
  • Preconditions:
    1. A contact form must be active on the site.
    2. An administrator must view or update the malicious entry in the plugin's dashboard.

3. Code Flow

  1. Submission: vxcf_form::create_entry_cf() (or similar for other form plugins) is triggered via the wpcf7_before_send_mail hook.
  2. Storage: The plugin iterates over $_POST and $_FILES. It saves the submission data, including the attacker's crafted keys, into the wp_vxcf_leads table (or similar) as serialized data or JSON.
  3. Admin Interaction: An administrator navigates to the "CRM Entries" page and selects the poisoned entry.
  4. Processing: The vxcf_form_pages::view_page() (inferred) function is called. It retrieves the stored fields.
  5. Sink: If the admin "Updates" the entry or triggers a "Delete File" action, the plugin compares the POST data against the stored fields. The "bracket parser" reshaping allows a manipulated $_POST key to be treated as a valid file path from the entry, which is then passed to unlink().

4. Nonce Acquisition Strategy

  • Unauthenticated Submission: Contact Form 7 often requires a REST API nonce (_wpcf7_unit_tag and potentially a nonce in headers), but it is usually available to anonymous users by fetching the page containing the form.
  • Admin Interaction: Accessing the admin dashboard requires standard session cookies. The "Update" or "Delete" actions in the admin panel will be protected by a WordPress nonce.
    • Action Name: vx_crm_ajax (for AJAX actions) or standard admin nonces.
    • JS Variable: Check window.vxcf_leads_data or similar localized scripts for nonce values.

5. Exploitation Strategy

  1. Environment Setup: Create a dummy file to delete: wp-content/pwn.txt.
  2. Reconnaissance:
    • Identify an active Contact Form 7 form ID by navigating to the homepage.
    • Note the form's required fields (name, email, etc.).
  3. Poisoning (Unauthenticated):
    • Submit a POST request to the CF7 endpoint.
    • Payload: Include a parameter like vxcf_file[../../../../wp-content/pwn.txt]=1.
  4. Triggering (Authenticated):
    • Log in as an administrator.
    • Navigate to wp-admin/admin.php?page=vxcf_leads.
    • Identify the ID of the new entry.
    • Navigate to the Edit page: wp-admin/admin.php?page=vxcf_leads&action=edit&id=<ID>.
    • Perform an "Update" or trigger the file removal logic.
  5. Verification: Check if wp-content/pwn.txt still exists.

6. Test Data Setup

  • Plugin Configuration: Ensure "Contact Form Entries" is active and CF7 is installed.
  • Target File: touch /var/www/html/wp-content/pwn.txt
  • Shortcode Page: Create a page with a form if none exists:
    wp post create --post_type=page --post_title="Contact" --post_status=publish --post_content='[contact-form-7 id="FORM_ID"]'
    

7. Expected Results

  • The unauthenticated submission should return a 200 OK status with a "mail_sent" or "validation_failed" response (the plugin saves data even if mail fails).
  • The admin viewing/updating the entry should result in the server calling unlink() on the path provided in the bracketed key.
  • The file wp-content/pwn.txt should be deleted from the filesystem.

8. Verification Steps (Post-Exploit)

# Check if the entry was saved in the database
wp db query "SELECT * FROM wp_vxcf_leads ORDER BY id DESC LIMIT 1;"

# Check if the file was deleted
ls /var/www/html/wp-content/pwn.txt
# Expected: "ls: cannot access ... No such file or directory"

9. Alternative Approaches

If the view_page direct trigger fails, investigate the ajax_actions function in includes/plugin-pages.php. There may be a delete_file action accessible via admin-ajax.php.

  • Payload for AJAX: action=actions_vxcf_leads&action2=delete_file&entry_id=<ID>&file_name=../../../../wp-content/pwn.txt
  • This would require capturing the vx_crm_ajax nonce first.
Research Findings
Static analysis — not yet PoC-verified

Summary

The 'Database for Contact Form 7' plugin allows unauthenticated attackers to delete arbitrary files on the server (e.g., wp-config.php) via path traversal. This occurs because the plugin stores attacker-supplied file paths from form submissions and subsequently calls unlink() on those paths without validation when an administrator views or updates the entry.

Vulnerable Code

// includes/plugin-pages.php lines 1188-1200
          if(is_array($db_files)){
          foreach($db_files as $k=>$file){
if(!isset($_POST['files_'.$name][$k])){   
    //delete old file
    if( file_exists($upload['dir'].$file)){
        
    @unlink($upload['dir'].$file);    
    }    
               }else{ 
             $files[]=$file;      
               }
          }

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/contact-form-entries/1.5.1/includes/plugin-pages.php\t2026-05-17 11:39:12.000000000 +0000\n+++ /home/deploy/wp-safety.org/data/plugin-versions/contact-form-entries/1.5.2/includes/plugin-pages.php\t2026-06-19 11:39:34.000000000 +0000\n@@ -1190,11 +1190,11 @@\n         }\n           if(is_array($db_files)){\n           foreach($db_files as $k=>$file){\n-if(!isset($_POST['files_'.$name][$k])){   \n+if(!isset($_POST['files_'.$name][$k])){  \n     //delete old file\n-    if( file_exists($upload['dir'].$file)){\n-        \n-    @unlink($upload['dir'].$file);    \n+   $real_file=realpath($upload['dir'].$file);\n+    if( file_exists($real_file) && strpos($real_file,'/crm_perks_uploads/') !== false){      \n+    @unlink($real_file);    \n     }    \n                }else{ \n              $files[]=$file;      \n--- /home/deploy/wp-safety.org/data/plugin-versions/contact-form-entries/1.5.1/templates/view.php\t2026-05-17 11:39:12.000000000 +0000\n+++ /home/deploy/wp-safety.org/data/plugin-versions/contact-form-entries/1.5.2/templates/view.php\t2026-06-19 11:39:34.000000000 +0000\n@@ -554,7 +554,7 @@\n     ?>\n <div class="vx_file_single">\n <?php echo esc_url($file_value); ?>  \n   <div>\n-  <input type="hidden" name="files_<?php echo esc_html($f_name.'['.$k.']') ?>" value="<?php echo esc_html($val) ?>" />\n+  <input type="hidden" name="files_<?php echo esc_html($f_name.'['.str_replace(array("[" , "]"),'',$k).']') ?>" value="<?php echo esc_html($val) ?>" />\n   <input type="file" id="vx_<?php echo esc_html($field['name']); ?>" <?php echo esc_html($req) ?> class="vx_input" name="<?php echo esc_html($f_name).'[]' ?>" autocomplete="off">\n  <a href="#" class="vx_del_link vx_float_right vx_remove_file"><?php _e('Remove','contact-form-entries') ?></a>\n   </div>

Exploit Outline

1. **Unauthenticated Submission:** The attacker identifies a Contact Form 7, WPForms, or Elementor form on the target site and submits a POST request. 2. **Path Traversal Payload:** The submission includes a field key designed to exploit PHP's bracket parsing, such as `vx_file[../../../../wp-config.php]`. The plugin stores this raw path in the database as a file attachment. 3. **Administrative Trigger:** An administrator logs into the WordPress dashboard and navigates to the 'CRM Entries' page to view or edit the specific submission. 4. **Execution:** When the administrator performs an update action, the plugin checks if the 'files' stored in the database are present in the current `$_POST` request. Because the attacker's path-based key is not present in the admin's legitimate update request, the plugin assumes the file was deleted by the user and executes `unlink()` on the traversal path, deleting the target file.

Check if your site is affected.

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