CVE-2026-8991

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

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
4.4
CVSS Score
4.4
CVSS Score
medium
Severity
1.3.9.8
Patched in
1d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
High
Privileges Required
High
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.3.9.7
PublishedJune 5, 2026
Last updatedJune 6, 2026

What Changed in the Fix

Changes introduced in v1.3.9.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

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 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:

  1. Data Retrieval (PHP): The plugin retrieves the stored settings using a helper function, likely dnd_cf7_settings(), within inc/dnd-upload-cf7.php.
  2. Localization: The values are passed to the frontend via wp_localize_script(), becoming part of a global JavaScript
Research Findings
Static analysis — not yet PoC-verified

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

diff -ru 1.3.9.7/assets/js/codedropz-uploader-min.js 1.3.9.8/assets/js/codedropz-uploader-min.js
--- 1.3.9.7/assets/js/codedropz-uploader-min.js	2026-04-17 04:16:40.000000000 +0000
+++ 1.3.9.8/assets/js/codedropz-uploader-min.js	2026-05-26 10:13:30.000000000 +0000
@@ -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.