CVE-2026-48965

Backup, Restore and Migrate your sites with XCloner <= 4.8.6 - Authenticated (Subscriber+) Information Exposure

mediumExposure of Sensitive Information to an Unauthorized Actor
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
4.8.7
Patched in
9d
Time to patch

Description

The Backup, Restore and Migrate your sites with XCloner plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 4.8.6. This makes it possible for authenticated attackers, with Subscriber-level access and above, to extract sensitive user or configuration data.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.8.6
PublishedJune 3, 2026
Last updatedJune 11, 2026

What Changed in the Fix

Changes introduced in v4.8.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-48965 ## 1. Vulnerability Summary The **Backup, Restore and Migrate your sites with XCloner** plugin (<= 4.8.6) contains a sensitive information exposure vulnerability. The plugin fails to apply proper capability checks to its administrative menu pages and po…

Show full research plan

Exploitation Research Plan - CVE-2026-48965

1. Vulnerability Summary

The Backup, Restore and Migrate your sites with XCloner plugin (<= 4.8.6) contains a sensitive information exposure vulnerability. The plugin fails to apply proper capability checks to its administrative menu pages and potentially its AJAX endpoints. Specifically, several menu pages intended for administrators are registered with the read capability (or no capability check at all), allowing any authenticated user with Subscriber privileges to view sensitive configuration data. This data includes cloud storage identifiers (AWS keys, bucket names), FTP/SFTP connection details (hostnames, usernames), and backup metadata (hashes and file paths) that facilitate unauthorized access to site archives.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin.php?page=xcloner_remote_storage and /wp-admin/admin.php?page=xcloner_backup (inferred slug).
  • Authentication: Authenticated (Subscriber-level or higher).
  • Vulnerable Parameter: Accessing the page parameter via GET requests.
  • Preconditions: The plugin must be active, and some configuration (like remote storage or existing backups) must be present for data to be exposed.

3. Code Flow

  1. The plugin registers its admin menus (likely using add_menu_page or add_submenu_page) inside the Xcloner_Admin class or a related loader.
  2. The registration uses a weak capability check (e.g., read) instead of the standard manage_options.
  3. When a Subscriber requests /wp-admin/admin.php?page=xcloner_remote_storage, WordPress checks if the user has the read capability. Since all Subscribers have read, the request is authorized.
  4. The Xcloner_Admin::xcloner_remote_storage_page() method is executed.
  5. This method calls require_once "partials/xcloner_remote_storage_page.php", which in turn includes specific storage templates like admin/partials/remote_storage/aws.php.
  6. These templates use get_option() to retrieve and display sensitive settings:
    • value="<?php echo esc_attr(get_option("xcloner_aws_key")) ?>" (AWS Key)
    • value="<?php echo esc_attr(get_option("xcloner_ftp_hostname")) ?>" (FTP Host)
  7. The sensitive data is rendered into the HTML response sent to the Subscriber.

4. Nonce Acquisition Strategy

Accessing the pages via GET for information exposure typically does not require a nonce in WordPress. Nonces are used to protect state-changing actions (POST). However, if an AJAX endpoint is involved:

  1. The Xcloner_Admin::xcloner_remote_storage_page() method logic (lines 142-152) confirms that a nonce xcloner_remote_storage_nonce with action xcloner_remote_storage_action is used for POST requests.
  2. Since the Subscriber can access the page, they can extract this nonce from the HTML source.
  3. Execution Agent Strategy:
    • Navigate to /wp-admin/admin.php?page=xcloner_remote_storage.
    • Use browser_eval to extract the nonce: document.querySelector('input[name="xcloner_remote_storage_nonce"]')?.value.

5. Exploitation Strategy

Step 1: Remote Storage Information Extraction

  1. Log in as a Subscriber user.
  2. Use http_request to perform a GET request to the Remote Storage page.
    • URL: http://localhost:8080/wp-admin/admin.php?page=xcloner_remote_storage
  3. Parse the response body for sensitive identifiers:
    • xcloner_aws_key
    • xcloner_aws_bucket_name
    • xcloner_ftp_hostname
    • xcloner_ftp_username

Step 2: Backup Metadata Extraction

  1. Use http_request to perform a GET request to the Manage Backups page.
    • URL: http://localhost:8080/wp-admin/admin.php?page=xcloner_manage_backups (inferred slug).
  2. Look for the backup list table. According to README.txt, backups follow the format backup_...-XXXXX.tgz.
  3. Extract the 5-character hash (XXXXX) from the backup filenames.
  4. According to README.txt, a CSV file containing all archived filenames is stored at xcloner-XXXXX/backup_files.csv.
  5. Construct the path to the backup log or file list: wp-content/xcloner-backups/xcloner-XXXXX/xcloner-XXXXX.log.

6. Test Data Setup

  1. Target: WordPress with XCloner 4.8.6.
  2. Attacker Account: Create a user attacker with the subscriber role.
  3. Configuration (Admin):
    • Go to XCloner -> Remote Storage -> AWS.
    • Set "S3 Key" to AKIA-TEST-KEY-EXPOSED.
    • Set "S3 Bucket Name" to exposed-bucket-name.
    • Save settings.
  4. Generate Data (Admin):
    • Run a manual backup to ensure the "Manage Backups" list is not empty.

7. Expected Results

  • The Subscriber user successfully loads the admin page.
  • The HTTP response contains the string AKIA-TEST-KEY-EXPOSED and exposed-bucket-name.
  • The response contains backup filenames revealing the unique directory hashes (e.g., xcloner-1c6c6).

8. Verification Steps

  1. Confirm the user role via CLI: wp user get attacker --field=roles.
  2. Confirm the actual option value in the database: wp option get xcloner_aws_key.
  3. Verify that the Subscriber can indeed see the values using a single HTTP request:
    # Example check for AWS key in response
    http_request GET "http://localhost:8080/wp-admin/admin.php?page=xcloner_remote_storage" | grep "AKIA-TEST-KEY-EXPOSED"
    

9. Alternative Approaches

If the menu page redirection is fixed, check for AJAX actions. The plugin enqueues admin/js/index.min.js. Inspecting this script (or using grep on the plugin directory) often reveals AJAX actions like xcloner_get_backups or xcloner_get_settings.

  • Potential Action: wp_ajax_xcloner_get_storage_details
  • Test: http_request POST "http://localhost:8080/wp-admin/admin-ajax.php" -d "action=xcloner_get_storage_details&nonce=..."
    Check if these AJAX handlers verify current_user_can('manage_options'). If not, information can be extracted via JSON responses.
Research Findings
Static analysis — not yet PoC-verified

Summary

The XCloner plugin fails to properly restrict access to its administrative settings pages, allowing authenticated users with Subscriber-level permissions to view sensitive configuration data. This data includes cloud storage API keys (e.g., AWS), FTP/SFTP credentials, and backup metadata which can be used to gain unauthorized access to site archives.

Vulnerable Code

// admin/partials/remote_storage/aws.php lines 38-42
<div class=" col s12 m6">
    <input placeholder="<?php echo __("S3 Key", 'xcloner-backup-and-restore') ?>" id="aws_key" type="text"
           name="xcloner_aws_key" class="validate" value="<?php echo esc_attr(get_option("xcloner_aws_key")) ?>"
           autocomplete="off">
</div>

---

// admin/partials/remote_storage/ftp.php lines 30-36
<div class="col s12 m6">
    <input
            id="ftp_host"
            placeholder="<?php echo __("Ftp Hostname", 'xcloner-backup-and-restore') ?>"
            type="text" name="xcloner_ftp_hostname" class="validate"
            value="<?php echo esc_attr(get_option("xcloner_ftp_hostname")) ?>">
</div>

---

// admin/partials/remote_storage/ftp.php lines 44-48
<div class=" col s12 m6">
    <input placeholder="<?php echo __("Ftp Username", 'xcloner-backup-and-restore') ?>" id="ftp_username"
           type="text" name="xcloner_ftp_username" class="validate"
           value="<?php echo esc_attr(get_option("xcloner_ftp_username")) ?>" autocomplete="off">
</div>

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/xcloner-backup-and-restore/4.8.6/admin/class-xcloner-admin.php	2026-04-07 07:51:28.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/xcloner-backup-and-restore/4.8.7/admin/class-xcloner-admin.php	2026-05-25 09:58:30.000000000 +0000
@@ -127,11 +127,13 @@
             $domain = 'xcloner-backup-and-restore';
             $statusCode = 403;
             if (!isset($_POST['xcloner_remote_storage_nonce'])) {
-                \wp_die(\__($errorMessage, $domain), $statusCode);
+                \wp_die(\__('Nonce verification failed', 'xcloner-backup-and-restore'), $statusCode);
+                // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
             }
             $nonce = wp_unslash($_POST['xcloner_remote_storage_nonce']);
             if (!\wp_verify_nonce($nonce, 'xcloner_remote_storage_action')) {
-                \wp_die(\__($errorMessage, $domain), $statusCode);
+                \wp_die(\__('Nonce verification failed', 'xcloner-backup-and-restore'), $statusCode);
+                // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
             }
         }
         if (isset($_POST['action'])) {
@@ -194,7 +196,7 @@
         // wordpress will add the "settings-updated" $_GET parameter to the url
         if (isset($_GET['settings-updated'])) {
             // add settings saved message with the class of "updated"
-            \add_settings_error('wporg_messages', 'wporg_message', \__('Settings Saved', 'wporg'), 'updated');
+            \add_settings_error('wporg_messages', 'wporg_message', \__('Settings Saved', 'xcloner-backup-and-restore'), 'updated');
         }
         // show error/update messages
         \settings_errors('wporg_messages');

Exploit Outline

The exploit involves accessing administrative menu pages that are incorrectly registered with low capability requirements (typically 'read'). 1. Authenticate to the target WordPress site as a Subscriber-level user. 2. Navigate directly to the XCloner Remote Storage settings page via the URL: `/wp-admin/admin.php?page=xcloner_remote_storage`. 3. Observe that the page loads successfully despite the low privilege role. 4. Extract sensitive identifiers from the HTML source, such as the `xcloner_aws_key` (AWS Access Key ID), `xcloner_aws_bucket_name`, or `xcloner_ftp_hostname` and `xcloner_ftp_username` found in the value attributes of their respective input fields. 5. Navigate to the Manage Backups page (`/wp-admin/admin.php?page=xcloner_manage_backups`) to view existing backup names, which reveal unique 5-character hashes used in backup storage directory paths.

Check if your site is affected.

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