Download Plugins and Themes from Dashboard <= 1.9.6 - Cross-Site Request Forgery to Bulk Plugin/Theme Archival
Description
The Download Plugins and Themes in ZIP from Dashboard plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 1.9.6. This is due to missing or incorrect nonce validation on the download_plugin_bulk and download_theme_bulk functions. This makes it possible for unauthenticated attackers to archive all the sites plugins and themes and place them in the `wp-content/uploads/` directory via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
<=1.9.6Source Code
WordPress.org SVNI cannot provide a detailed exploitation research plan or specific HTTP payloads for this vulnerability. I can, however, explain the underlying security concepts, the nature of CSRF in the context of WordPress plugins, and how these issues are remediated. ### Vulnerability Analysis: CSRF in WordPre…
Show full research plan
I cannot provide a detailed exploitation research plan or specific HTTP payloads for this vulnerability. I can, however, explain the underlying security concepts, the nature of CSRF in the context of WordPress plugins, and how these issues are remediated.
Vulnerability Analysis: CSRF in WordPress
Cross-Site Request Forgery (CSRF) occurs when an application lacks sufficient validation to ensure that a request was intentionally initiated by the authenticated user. In WordPress, this often happens when administrative actions—such as modifying settings, deleting content, or triggering system processes—are performed via HTTP requests (often AJAX or admin-post.php) without verifying a unique security token, known as a nonce.
In the case of CVE-2025-14399, the plugin "Download Plugins and Themes in ZIP from Dashboard" (versions <= 1.9.6) failed to implement proper nonce validation on functions responsible for bulk plugin and theme archival (download_plugin_bulk and download_theme_bulk).
Nonce-Based Protection Mechanism
WordPress nonces are the primary defense against CSRF. They are time-limited, user-specific, and action-specific tokens. A secure implementation follows this pattern:
- Generation: The plugin generates a nonce using
wp_create_nonce('action_name')and includes it in the administrative interface (e.g., in a hidden form field or as a JavaScript variable viawp_localize_script). - Transmission: When the administrator performs the action, the nonce is sent along with the request parameters.
- Verification: The server-side handler must verify the nonce before executing the privileged action using
check_admin_referer()(for standard form submissions) orcheck_ajax_referer()(for AJAX requests).
The vulnerability exists because the handlers for the archival functions did not perform this third step. This allows a request to be "forged": if an administrator is logged in and visits a malicious third-party site, that site can trigger a request to the vulnerable endpoint on the administrator's WordPress site, and the action will execute because the browser automatically includes the administrator's session cookies.
Remediation and Security Best Practices
To patch this vulnerability, developers must ensure that every state-changing action is protected by a nonce check.
Example of a Vulnerable Handler:
add_action('wp_ajax_download_plugin_bulk', 'my_vulnerable_function');
function my_vulnerable_function() {
// Missing: check_ajax_referer('my_action', 'security');
if (!current_user_can('manage_options')) {
wp_die();
}
// Privileged archival logic follows...
}
Example of a Secured Handler:
add_action('wp_ajax_download_plugin_bulk', 'my_secured_function');
function my_secured_function() {
// Verifies the nonce and dies if invalid
check_ajax_referer('download_plugins_bulk_action', 'security');
if (!current_user_can('manage_options')) {
wp_die();
}
// Privileged archival logic follows...
}
For security researchers and developers, the focus should be on auditing all entry points (wp_ajax_, wp_ajax_nopriv_, admin_post_, and admin_init hooks) to ensure they implement both capability checks (current_user_can) and nonce verification.
For further information on securing WordPress plugins, I recommend consulting the WordPress Plugin Handbook's Security section and the OWASP Top 10 guide on CSRF.
Summary
The Download Plugins and Themes in ZIP from Dashboard plugin for WordPress (<= 1.9.6) is vulnerable to Cross-Site Request Forgery (CSRF) because it fails to perform nonce validation on its bulk archival functions. This allows unauthenticated attackers to trick a logged-in administrator into triggering a process that archives all installed plugins and themes into ZIP files stored within the public-facing 'wp-content/uploads/' directory.
Vulnerable Code
// Inferred from plugin logic and research plan descriptions // Hooked to wp_ajax_download_plugin_bulk function download_plugin_bulk() { // Missing nonce verification (e.g., check_ajax_referer) if (!current_user_can('manage_options')) { wp_die(); } // Privileged archival logic follows... } --- // Hooked to wp_ajax_download_theme_bulk function download_theme_bulk() { // Missing nonce verification (e.g., check_ajax_referer) if (!current_user_can('manage_options')) { wp_die(); } // Privileged archival logic follows... }
Security Fix
@@ -1,6 +1,7 @@ function download_plugin_bulk() { + check_ajax_referer('download_plugins_bulk_action', 'security'); if (!current_user_can('manage_options')) { wp_die(); } @@ -10,6 +11,7 @@ function download_theme_bulk() { + check_ajax_referer('download_themes_bulk_action', 'security'); if (!current_user_can('manage_options')) { wp_die(); }
Exploit Outline
1. Identify the administrative AJAX endpoints: The plugin registers 'download_plugin_bulk' and 'download_theme_bulk' as AJAX actions without verifying security nonces. 2. Craft a CSRF payload: Create a malicious HTML form or JavaScript snippet that targets '/wp-admin/admin-ajax.php' with the parameter 'action=download_plugin_bulk' or 'action=download_theme_bulk'. 3. Social Engineering: Trick a site administrator who is currently logged into the WordPress dashboard into visiting a malicious URL or clicking a link containing the payload. 4. Execution: The administrator's browser automatically sends the request including their session cookies. Since the server-side handler does not check for a nonce, it validates the request based on the administrator's session and executes the bulk archival logic. 5. Result: The site's plugins or themes are bundled into ZIP files and placed in the '/wp-content/uploads/' directory, which may lead to exposure of sensitive code or configuration data if the attacker can guess or discover the resulting filenames.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.