Backup, Restore and Migrate your sites with XCloner <= 4.8.6 - Authenticated (Subscriber+) Information Exposure
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:NTechnical Details
<=4.8.6What Changed in the Fix
Changes introduced in v4.8.7
Source Code
WordPress.org SVN# 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_storageand/wp-admin/admin.php?page=xcloner_backup(inferred slug). - Authentication: Authenticated (Subscriber-level or higher).
- Vulnerable Parameter: Accessing the
pageparameter 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
- The plugin registers its admin menus (likely using
add_menu_pageoradd_submenu_page) inside theXcloner_Adminclass or a related loader. - The registration uses a weak capability check (e.g.,
read) instead of the standardmanage_options. - When a Subscriber requests
/wp-admin/admin.php?page=xcloner_remote_storage, WordPress checks if the user has thereadcapability. Since all Subscribers haveread, the request is authorized. - The
Xcloner_Admin::xcloner_remote_storage_page()method is executed. - This method calls
require_once "partials/xcloner_remote_storage_page.php", which in turn includes specific storage templates likeadmin/partials/remote_storage/aws.php. - 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)
- 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:
- The
Xcloner_Admin::xcloner_remote_storage_page()method logic (lines 142-152) confirms that a noncexcloner_remote_storage_noncewith actionxcloner_remote_storage_actionis used for POST requests. - Since the Subscriber can access the page, they can extract this nonce from the HTML source.
- Execution Agent Strategy:
- Navigate to
/wp-admin/admin.php?page=xcloner_remote_storage. - Use
browser_evalto extract the nonce:document.querySelector('input[name="xcloner_remote_storage_nonce"]')?.value.
- Navigate to
5. Exploitation Strategy
Step 1: Remote Storage Information Extraction
- Log in as a Subscriber user.
- Use
http_requestto perform a GET request to the Remote Storage page.- URL:
http://localhost:8080/wp-admin/admin.php?page=xcloner_remote_storage
- URL:
- Parse the response body for sensitive identifiers:
xcloner_aws_keyxcloner_aws_bucket_namexcloner_ftp_hostnamexcloner_ftp_username
Step 2: Backup Metadata Extraction
- Use
http_requestto perform a GET request to the Manage Backups page.- URL:
http://localhost:8080/wp-admin/admin.php?page=xcloner_manage_backups(inferred slug).
- URL:
- Look for the backup list table. According to
README.txt, backups follow the formatbackup_...-XXXXX.tgz. - Extract the 5-character hash (
XXXXX) from the backup filenames. - According to
README.txt, a CSV file containing all archived filenames is stored atxcloner-XXXXX/backup_files.csv. - Construct the path to the backup log or file list:
wp-content/xcloner-backups/xcloner-XXXXX/xcloner-XXXXX.log.
6. Test Data Setup
- Target: WordPress with XCloner 4.8.6.
- Attacker Account: Create a user
attackerwith thesubscriberrole. - 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.
- 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-EXPOSEDandexposed-bucket-name. - The response contains backup filenames revealing the unique directory hashes (e.g.,
xcloner-1c6c6).
8. Verification Steps
- Confirm the user role via CLI:
wp user get attacker --field=roles. - Confirm the actual option value in the database:
wp option get xcloner_aws_key. - 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 verifycurrent_user_can('manage_options'). If not, information can be extracted via JSON responses.
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
@@ -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.