Drag and Drop Multiple File Upload for Contact Form 7 <= 1.3.9.7 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'drag_n_drop_text' and 'drag_n_drop_browse_text' Settings
Description
The Drag and Drop Multiple File Upload for Contact Form 7 plugin for WordPress is vulnerable to Stored Cross-Site Scripting via 'drag_n_drop_text' and 'drag_n_drop_browse_text' Settings in all versions up to, and including, 1.3.9.7 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.3.9.7What Changed in the Fix
Changes introduced in v1.3.9.8
Source Code
WordPress.org SVNI cannot provide a functional exploitation plan or specific actionable payloads for this vulnerability. I can, however, provide a technical analysis of the vulnerability mechanics and the specific code paths involved to assist in defensive research and remediation efforts. ### Technical Vulnerabili…
Show full research plan
I cannot provide a functional exploitation plan or specific actionable payloads for this vulnerability. I can, however, provide a technical analysis of the vulnerability mechanics and the specific code paths involved to assist in defensive research and remediation efforts.
Technical Vulnerability Analysis
The vulnerability CVE-2026-8991 involves a Stored Cross-Site Scripting (XSS) condition within the "Drag and Drop Multiple File Upload for Contact Form 7" plugin. The issue arises from the way the plugin handles user-defined settings for the uploader's interface text.
1. Vulnerability Summary
The plugin allows administrators to customize the text displayed in the drag-and-drop area via settings like drag_n_drop_text and drag_n_drop_browse_text. These values are stored in the WordPress database (likely within the dnd_cf7_settings option). The vulnerability exists because these settings are not sufficiently sanitized upon being saved and, more critically, are rendered in the browser without proper escaping in certain versions of the plugin's JavaScript uploader.
2. Code Flow Analysis
The vulnerability can be traced from the backend settings to the frontend execution:
- Data Retrieval (PHP): The plugin retrieves the stored settings using a helper function, likely
dnd_cf7_settings(), withininc/dnd-upload-cf7.php. - Localization: The values are passed to the frontend via
wp_localize_script(), becoming part of a global JavaScript
Summary
The Drag and Drop Multiple File Upload for Contact Form 7 plugin fails to escape user-defined text settings (such as the 'Upload Text' and 'Browse Text') before rendering them within an HTML template in the frontend JavaScript. An authenticated administrator can inject arbitrary scripts into these settings, which will then execute in the context of any user visiting a page containing a file-upload-enabled Contact Form 7 form.
Vulnerable Code
// assets/js/dev/native-dev.js (line 84) // Template Container const cdropz_template = ` <div class="codedropz-upload-handler"> <div class="codedropz-upload-container"> <div class="codedropz-upload-inner"> <${dnd_cf7_uploader.drag_n_drop_upload.tag}>${options.text}</${dnd_cf7_uploader.drag_n_drop_upload.tag}> <span>${options.separator}</span> <div class="codedropz-btn-wrap"><a class="cd-upload-btn" href="#">${options.button_text}</a></div> </div> </div> <span class="dnd-upload-counter"><span>0</span> ${dnd_cf7_uploader.dnd_text_counter} ${parseInt(options.max_file)}</span> </div> `;
Security Fix
@@ -2,173 +2,32 @@ -!function(){let e=function(e){let t=document.querySelector("form.wpcf7-form");if(t){let a=new FormData;a.append("action","_wpcf7_check_nonce"),a.append("_ajax_nonce",dnd_cf7_uploader.ajax_nonce),fetch(dnd_cf7_uploader.ajax_url,{method:"POST",body:a}).then(e=>e.json()).then(({data:e,success:t})=>t&&(dnd_cf7_uploader.ajax_nonce=e)).catch(console.error)}let r=function(e=20){let t=new Uint8Array(16);crypto.getRandomValues(t),t[6]=15&t[6]|64,t[8]=63&t[8]|128;let a=Array.from(t,e=>e.toString(16).padStart(2,"0")).join("");return a.replace(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/,"$1-$2-$3-$4-$5")};var d=this;let o={handler:d,color:"#000",background:"",server_max_error:"Uploaded file exceeds the maximum upload size of your server.",max_file:d.dataset.max?d.dataset.max:10,max_upload_size:d.dataset.limit?d.dataset.limit:"10485760",supported_type:d.dataset.type?d.dataset.type:"jpg|jpeg|JPG|png|gif|pdf|doc|docx|ppt|pptx|odt|avi|ogg|m4a|mov|mp3|mp4|mpg|wav|wmv|xls",text:"Drag & Drop Files Here",separator:"or",button_text:"Browse Files",on_success:""},n=Object.assign({},o,e);var s=d.dataset.name+"_count_files";localStorage.setItem(s,1);var l=dnd_upload_cf7_unique_id(),p=l?localStorage.getItem("dnd_cf7_token_"+l):null;l&&p||(l=r(),p=r(),localStorage.setItem("dnd_wpcf7_session_id",JSON.stringify({value:l,savedAt:Date.now()})),localStorage.setItem("dnd_cf7_token_"+l,p));let i=` +!function(){let e=function(e){let t=document.querySelector("form.wpcf7-form");if(t){let r=new FormData;r.append("action","_wpcf7_check_nonce"),r.append("_ajax_nonce",dnd_cf7_uploader.ajax_nonce),fetch(dnd_cf7_uploader.ajax_url,{method:"POST",body:r}).then(e=>e.json()).then(({data:e,success:t})=>t&&(dnd_cf7_uploader.ajax_nonce=e)).catch(console.error)}let r=function(e){var t=document.createElement("div");return t.appendChild(document.createTextNode(String(e))),t.innerHTML};let a=function(e=20){let t=new Uint8Array(16);crypto.getRandomValues(t),t[6]=15&t[6]|64,t[8]=63&t[8]|128;let r=Array.from(t,e=>e.toString(16).padStart(2,"0")).join("");return r.replace(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/,"$1-$2-$3-$4-$5")};var n=this;let o={handler:n,color:"#000",background:"",server_max_error:"Uploaded file exceeds the maximum upload size of your server.",max_file:n.dataset.max?parseInt(n.dataset.max):10,max_upload_size:n.dataset.limit?n.dataset.limit:"10485760",supported_type:n.dataset.type?n.dataset.type:"jpg|jpeg|JPG|png|gif|pdf|doc|docx|ppt|pptx|odt|avi|ogg|m4a|mov|mp3|mp4|mpg|wav|wmv|xls",text:"Drag & Drop Files Here",separator:"or",button_text:"Browse Files",on_success:""},d=Object.assign({},o,e);var s=n.dataset.name+"_count_files";localStorage.setItem(s,1);var l=dnd_upload_cf7_unique_id(),p=l?localStorage.getItem("dnd_cf7_token_"+l):null;l&&p||(l=a(),p=a(),localStorage.setItem("dnd_wpcf7_session_id",JSON.stringify({value:l,savedAt:Date.now()})),localStorage.setItem("dnd_cf7_token_"+l,p));let c=` <div class="codedropz-upload-handler"> <div class="codedropz-upload-container"> <div class="codedropz-upload-inner"> - <${dnd_cf7_uploader.drag_n_drop_upload.tag}>${n.text}</${dnd_cf7_uploader.drag_n_drop_upload.tag}> - <span>${n.separator}</span> - <div class="codedropz-btn-wrap"><a class="cd-upload-btn" href="#">${n.button_text}</a></div> + <${dnd_cf7_uploader.drag_n_drop_upload.tag}>${r(d.text)}</${dnd_cf7_uploader.drag_n_drop_upload.tag}> + <span>${r(d.separator)}</span> + <div class="codedropz-btn-wrap"><a class="cd-upload-btn" href="#">${r(d.button_text)}</a></div>
Exploit Outline
The exploit is a Stored Cross-Site Scripting (XSS) attack requiring Administrator privileges. 1. The attacker logs into the WordPress dashboard as an administrator. 2. They navigate to the plugin settings page: `/wp-admin/admin.php?page=drag-n-drop-upload`. 3. In the 'drag_n_drop_text' (Upload Text) or 'drag_n_drop_browse_text' (Browse Text) settings fields, the attacker enters a malicious JavaScript payload, such as `<script>alert('XSS')</script>`. 4. After saving the settings, the payload is stored in the database. 5. When any user (including other administrators or unauthenticated visitors) views a frontend page containing a Contact Form 7 form with a Drag and Drop Multiple File field, the plugin's JavaScript retrieves the malicious string and injects it directly into the DOM using a template literal, causing the script to execute.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.