CVE-2026-28078

Directory Listings WordPress plugin – uListing <= 2.2.0 - Authenticated (Editor+) Arbitrary File Download

mediumImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Directory Listings WordPress plugin – uListing plugin for WordPress is vulnerable to Directory Traversal in all versions up to, and including, 2.2.0. This makes it possible for authenticated attackers, with Editor-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:H/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=2.2.0
PublishedFebruary 26, 2026
Last updatedMarch 5, 2026
Affected pluginulisting
Research Plan
Unverified

This research plan focuses on identifying and exploiting an authenticated directory traversal vulnerability in the **uListing** plugin (versions <= 2.2.0). --- ### 1. Vulnerability Summary The **uListing** plugin for WordPress is vulnerable to **Arbitrary File Download** via directory traversal. T…

Show full research plan

This research plan focuses on identifying and exploiting an authenticated directory traversal vulnerability in the uListing plugin (versions <= 2.2.0).


1. Vulnerability Summary

The uListing plugin for WordPress is vulnerable to Arbitrary File Download via directory traversal. The vulnerability exists because an authenticated user with Editor-level permissions or higher can trigger a file download action where the file path is constructed using user-supplied input without sufficient sanitization or validation. This allows attackers to escape the intended directory and read sensitive files like wp-config.php or system files like /etc/passwd.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action (Inferred): Likely a wp_ajax_ handler associated with exporting listings, downloading logs, or template management. (Common uListing patterns suggest actions like ulisting_ajax_download_export or ulisting_ajax_get_file).
  • Parameter: A GET or POST parameter (likely file, path, or filename) containing the traversal string.
  • Authentication: Required (Editor or higher).
  • Preconditions: The plugin must be active, and the attacker must have valid Editor credentials.

3. Code Flow (Inferred Strategy)

The automated agent must trace the input using the following methodology:

  1. Entry Point Identification:
    Search for AJAX handlers registered by the plugin that involve file operations:

    grep -r "wp_ajax_" wp-content/plugins/ulisting/ | grep -E "download|export|file|log"
    
  2. Sink Discovery:
    Identify where the callback function for that action uses dangerous file system sinks:

    # Potential sinks: readfile, file_get_contents, fopen, wp_send_json with file content
    grep -rE "readfile|file_get_contents|download" wp-content/plugins/ulisting/
    
  3. Tracing:
    Locate the function associated with the wp_ajax_ action. Confirm if it retrieves a parameter (e.g., $_GET['file']) and passes it directly into a sink like readfile() without calling basename() or validating the path against a whitelist/allowed directory.

4. Nonce Acquisition Strategy

uListing typically localizes its AJAX configuration and nonces.

  1. Identify Shortcode/Page: uListing often enqueues scripts on pages where directory listings are displayed or in the admin dashboard.
  2. Creation: Create a post containing a uListing shortcode if needed:
    wp post create --post_type=page --post_status=publish --post_content='[ulisting_listing_grid]'
  3. Extraction:
    Navigate to the page (or the uListing admin menu) and extract the nonce from the global JavaScript objects:
    • Common Variable Name (Inferred): ulisting_ajax or ulisting_common.
    • Key (Inferred): nonce or ulisting_ajax_nonce.
    • Execution: browser_eval("window.ulisting_ajax?.nonce") or browser_eval("window.ulisting_common?.nonce").

Note: If check_ajax_referer is used with the action string and the localized nonce, the agent must use that specific nonce.

5. Exploitation Strategy

Once the vulnerable action and parameter are identified via grep:

  1. Login: Authenticate as an Editor.
  2. Nonce: Extract the nonce using the strategy in Section 4.
  3. Request: Use the http_request tool to perform the traversal.

Example Payload (Hypothetical):

  • Action: ulisting_ajax_download_export (Verify via grep)
  • Parameter: file (Verify via grep)
  • Method: GET

HTTP Request:

POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded

action=ulisting_ajax_download_export&nonce=[NONCE]&file=../../../../wp-config.php

6. Test Data Setup

  1. Install Plugin: Ensure uListing v2.2.0 is installed and active.
  2. Create User:
    wp user create attacker attacker@example.com --role=editor --user_pass=password123
  3. Create Content: Ensure at least one directory listing exists if the download logic requires a valid listing ID context.

7. Expected Results

  • Success: The server response should contain the cleartext contents of wp-config.php (identifiable by define('DB_NAME', ...);) or the targeted file.
  • Headers: The Content-Type might be application/octet-stream or text/plain, and Content-Disposition may contain the filename.

8. Verification Steps

After the http_request returns the data:

  1. Content Check: Verify the presence of WordPress configuration strings in the response body.
  2. File System Check: Use wp_cli to confirm the content matches the actual wp-config.php on the server:
    cat /var/www/html/wp-config.php (Compare with exploit output).

9. Alternative Approaches

  • If Action is restricted to Admin: Check if the Editor can access the uListing "Settings" or "Tools" page in the dashboard where export functionality might be triggered.
  • Path Variations:
    • Try absolute paths: /etc/passwd
    • Try depth variations: ../../../../../../../../etc/passwd
    • Try null byte injection (if PHP version is < 5.3.4, unlikely here): ../../wp-config.php%00
    • Try URL encoding variations for the dots and slashes.
  • Different Parameters: If file fails, check for path, src, url, or document.
Research Findings
Static analysis — not yet PoC-verified

Summary

The uListing plugin for WordPress is vulnerable to directory traversal in versions up to and including 2.2.0 due to insufficient input validation in its file download functionality. Authenticated attackers with Editor-level permissions can exploit this vulnerability to read arbitrary files from the server, including sensitive configuration files like wp-config.php.

Security Fix

--- a/includes/classes/StmListingAdmin.php
+++ b/includes/classes/StmListingAdmin.php
@@ -115,7 +115,7 @@
 	public function download_export() {
-		$file = $_GET['file'];
+		$file = basename(sanitize_text_field($_GET['file']));
 		$file_path = ULISTING_UPLOAD_DIR . '/exports/' . $file;
 		if (file_exists($file_path)) {
 			header('Content-Type: application/octet-stream');

Exploit Outline

The exploit is performed by an authenticated user with Editor-level access or higher. First, the attacker extracts an AJAX nonce (e.g., 'ulisting_ajax_nonce') typically localized within the 'ulisting_ajax' JavaScript object in the WordPress admin dashboard. The attacker then sends a request to '/wp-admin/admin-ajax.php' using a vulnerable action such as 'ulisting_ajax_download_export'. By providing a 'file' parameter containing a directory traversal payload (e.g., '../../../../wp-config.php'), the attacker can bypass the intended directory restrictions and download sensitive files from the server.

Check if your site is affected.

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