Drag and Drop Multiple File Upload for Contact Form 7 <= 1.3.9.2 - Missing Authorization to Unauthenticated File Deletion
Description
The Drag and Drop Multiple File Upload for Contact Form 7 plugin for WordPress is vulnerable to unauthorized modification of data due to a missing ownership check in the dnd_codedropz_upload_delete() function in all versions up to, and including, 1.3.9.2. This makes it possible for unauthenticated attackers to delete arbitrary uploaded files when the "Send attachments as links" setting is enabled.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.3.9.2Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-14457 ## 1. Vulnerability Summary The **Drag and Drop Multiple File Upload for Contact Form 7** plugin (<= 1.3.9.2) contains a missing authorization vulnerability in its AJAX handler `dnd_codedropz_upload_delete()`. While the function performs a nonce check, i…
Show full research plan
Exploitation Research Plan: CVE-2025-14457
1. Vulnerability Summary
The Drag and Drop Multiple File Upload for Contact Form 7 plugin (<= 1.3.9.2) contains a missing authorization vulnerability in its AJAX handler dnd_codedropz_upload_delete(). While the function performs a nonce check, it fails to verify the ownership or "session-boundedness" of the file being deleted. When the plugin setting "Send attachments as links" is enabled, uploaded files are stored on the server. An unauthenticated attacker can obtain a valid nonce from the frontend and subsequently delete arbitrary files within the plugin's upload directory by predicting or obtaining their filenames.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
dnd_codedropz_upload_delete - Method:
POST - Authentication: Unauthenticated (via
wp_ajax_nopriv_hook) - Vulnerable Parameter:
file(the filename/path to be deleted) - Precondition: The "Send attachments as links" option must be enabled in the Contact Form 7 "Drag and Drop Upload" settings.
3. Code Flow
- Registration: The plugin registers the AJAX actions in the main plugin file or an initialization class:
add_action( 'wp_ajax_dnd_codedropz_upload_delete', 'dnd_codedropz_upload_delete' ); add_action( 'wp_ajax_nopriv_dnd_codedropz_upload_delete', 'dnd_codedropz_upload_delete' ); - Entry Point:
dnd_codedropz_upload_delete()ininc/ajax-functions.php(or similar) is invoked. - Nonce Verification: It calls
check_ajax_referer( 'dnd_codedropz_upload_nonce', 'nonce' ). - Processing:
- It retrieves the filename from
$_POST['file']. - It constructs the file path based on the plugin's upload directory (typically
wp-content/uploads/wpcf7_drag-n-drop_uploads/tmp/or similar).
- It retrieves the filename from
- Sink: The code calls
unlink( $file_path )orwp_delete_attachment()without checking if the current requester is the one who uploaded the file.
4. Nonce Acquisition Strategy
The plugin exposes the required nonce to unauthenticated users on any page where a Contact Form 7 form with the "Drag and Drop" field is present.
- Identify Shortcode: The plugin's field is added to CF7 using the
[drag-and-drop-file]tag. - Create Test Page:
- Create a CF7 form containing
[drag-and-drop-file file-limit:10 "upload-field"]. - Create a WordPress page with the shortcode for that form:
[contact-form-7 id="XX" title="Test Form"].
- Create a CF7 form containing
- Extract Nonce via Browser:
- Navigate to the page.
- The plugin localizes data into a JavaScript object, typically
dnd_cf7_uploader. - JS Variable:
dnd_cf7_uploader.ajax_nonceordnd_cf7_uploader.nonce. - Execution Command:
browser_eval("window.dnd_cf7_uploader?.ajax_nonce").
5. Exploitation Strategy
- Preparation:
- Identify/Create a file to delete. In a real scenario, the attacker would first upload a file (which returns the filename) or guess the names of files uploaded by others.
- Obtain the
dnd_codedropz_upload_nonceusing the strategy in Section 4.
- Execute Deletion:
- Send a POST request to
admin-ajax.php. - URL:
http://<target>/wp-admin/admin-ajax.php - Body (URL-encoded):
action=dnd_codedropz_upload_delete&nonce=<NONCE>&file=<TARGET_FILENAME> - Note: The
fileparameter might require just the basename or a relative path depending on the exact plugin version implementation.
- Send a POST request to
6. Test Data Setup
- Install/Activate: Contact Form 7 and Drag and Drop Multiple File Upload for Contact Form 7 (<= 1.3.9.2).
- Configure Plugin:
- Go to CF7 -> Drag and Drop Upload.
- Ensure "Send attachments as links" is checked.
- Create Form:
- Add a form with
[drag-and-drop-file drag-upload-1]. - Place form shortcode on a public page
/test-upload-page/.
- Add a form with
- Create Target File:
- Manually upload a file via the form or place a file in
wp-content/uploads/wpcf7_drag-n-drop_uploads/namedsecret-data.txt.
- Manually upload a file via the form or place a file in
7. Expected Results
- The server should return a
200 OKresponse (likely with a JSON success message or1). - The file
wp-content/uploads/wpcf7_drag-n-drop_uploads/secret-data.txt(or thetmp/subdirectory) will be deleted from the filesystem.
8. Verification Steps
- Filesystem Check: Use WP-CLI or shell to verify the file is gone.
ls /var/www/html/wp-content/uploads/wpcf7_drag-n-drop_uploads/secret-data.txt- Expected Result:
ls: cannot access ...: No such file or directory.
- Expected Result:
9. Alternative Approaches
- Path Traversal: Check if the
fileparameter is vulnerable to path traversal (e.g.,../../wp-config.php). Theunlinksink is particularly dangerous if the plugin doesn't usebasename()on the input. - Attachment Deletion: If the plugin uses
wp_delete_attachment( $id ), attempt to pass an integerfileID of a legitimate site attachment (e.g., a header image) to test for broader unauthorized deletion. - Directory Guessing: If the filename includes a hash or timestamp, attempt to find a leakage point in the CF7 submission logs or email if "Send as links" is active.
Summary
The Drag and Drop Multiple File Upload for Contact Form 7 plugin allows unauthenticated attackers to delete arbitrary files in the plugin's temporary upload directory. This occurs because the AJAX handler for file deletion performs a nonce check but fails to verify if the requester is the owner of the file, particularly when the 'Send attachments as links' setting is enabled.
Vulnerable Code
// inc/ajax-functions.php (approximate location based on plugin structure) add_action( 'wp_ajax_dnd_codedropz_upload_delete', 'dnd_codedropz_upload_delete' ); add_action( 'wp_ajax_nopriv_dnd_codedropz_upload_delete', 'dnd_codedropz_upload_delete' ); function dnd_codedropz_upload_delete() { // Only verifies the nonce, not the user's authority over the specific file check_ajax_referer( 'dnd_codedropz_upload_nonce', 'nonce' ); $file = isset( $_POST['file'] ) ? sanitize_text_field( $_POST['file'] ) : ''; $upload_dir = wp_upload_dir(); $file_path = $upload_dir['basedir'] . '/wpcf7_drag-n-drop_uploads/tmp/' . $file; if ( file_exists( $file_path ) ) { unlink( $file_path ); } wp_die(); }
Security Fix
@@ -10,6 +10,13 @@ check_ajax_referer( 'dnd_codedropz_upload_nonce', 'nonce' ); $file = isset( $_POST['file'] ) ? sanitize_text_field( $_POST['file'] ) : ''; + + // Verify that the file to be deleted belongs to the current session + $session_files = isset($_SESSION['dnd_uploaded_files']) ? $_SESSION['dnd_uploaded_files'] : array(); + if ( ! in_array( $file, $session_files ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized' ) ); + wp_die(); + } + $upload_dir = wp_upload_dir(); $file_path = $upload_dir['basedir'] . '/wpcf7_drag-n-drop_uploads/tmp/' . $file;
Exploit Outline
The exploit target is the `dnd_codedropz_upload_delete` AJAX action. An unauthenticated attacker first navigates to any public page containing a form with the 'Drag and Drop' field to extract a valid `dnd_codedropz_upload_nonce` from the localized `dnd_cf7_uploader` JavaScript object. The attacker then identifies a target filename within the plugin's temporary upload directory (either by uploading a file themselves or predicting filenames). Finally, the attacker sends a POST request to `wp-admin/admin-ajax.php` with the `action` set to `dnd_codedropz_upload_delete`, providing the acquired nonce and the target filename in the `file` parameter, causing the server to delete the file from the filesystem.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.