CVE-2025-14944

Backup Migration <= 2.0.0 - Missing Authorization to Unauthenticated Backup Upload to Offline Storage

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.1.0
Patched in
2d
Time to patch

Description

The Backup Migration plugin for WordPress is vulnerable to Missing Authorization in all versions up to, and including, 2.0.0. This is due to a missing capability check on the 'initializeOfflineAjax' function and lack of proper nonce verification. The endpoint only validates against hardcoded tokens which are publicly exposed in the plugin's JavaScript. This makes it possible for unauthenticated attackers to trigger the backup upload queue processing, potentially causing unexpected backup transfers to configured cloud storage targets and resource exhaustion.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.0.0
PublishedApril 6, 2026
Last updatedApril 7, 2026
Affected pluginbackup-backup

What Changed in the Fix

Changes introduced in v2.1.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-14944 (Backup Migration) ## 1. Vulnerability Summary The **Backup Migration** plugin (up to 2.0.0) contains a Missing Authorization vulnerability in its offline storage handling logic. The function `initializeOfflineAjax` is registered as an unauthenticated AJ…

Show full research plan

Exploitation Research Plan: CVE-2025-14944 (Backup Migration)

1. Vulnerability Summary

The Backup Migration plugin (up to 2.0.0) contains a Missing Authorization vulnerability in its offline storage handling logic. The function initializeOfflineAjax is registered as an unauthenticated AJAX action (wp_ajax_nopriv_...) but fails to implement a current_user_can() capability check or a standard WordPress nonce verification. Instead, it relies on a "token" that is hardcoded or generated and then exposed to all users through localized JavaScript variables. This allows an unauthenticated attacker to trigger backup upload queue processing, leading to resource exhaustion or unauthorized data transfers to configured cloud storage.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: bmi_initialize_offline_backup (triggers the initializeOfflineAjax function).
  • Required Parameter: token (The "offline token").
  • Authentication: Unauthenticated (No login required).
  • Preconditions: The plugin must be active. Some cloud/offline storage configuration may need to be present for the upload to actually "exhaust resources," but the trigger itself is the vulnerability.

3. Code Flow

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php with action=bmi_initialize_offline_backup.
  2. Hook Registration: The plugin registers the action (inferred location: includes/backup-methods/offline/offline.php or includes/initializer.php):
    add_action('wp_ajax_bmi_initialize_offline_backup', 'initializeOfflineAjax');
    add_action('wp_ajax_nopriv_bmi_initialize_offline_backup', 'initializeOfflineAjax');
    
  3. Vulnerable Function: The initializeOfflineAjax function executes.
  4. Token Validation: It checks if $_POST['token'] matches a value stored in the database (or a hardcoded one).
  5. Localization: This same token is made available to the frontend JS via wp_localize_script:
    wp_localize_script('bmi-backup-js', 'bmi_ajax_var', array(
        'bmi_offline_token' => $offline_token,
        // ...
    ));
    
  6. Execution: If the token matches, it proceeds to call methods that process the backup upload queue without checking if the requester is an administrator.

4. Token Acquisition Strategy

Nonces are not used here, but a "token" is. The token is exposed in the bmi_ajax_var global JavaScript object.

  1. Navigate: Use browser_navigate to the WordPress homepage or any page where the plugin might load.
  2. Identification: The plugin typically enqueues its main JS on all admin pages and sometimes on the frontend if certain features are enabled.
  3. JS Evaluation:
    • Execute: browser_eval("window.bmi_ajax_var?.bmi_offline_token")
    • If bmi_ajax_var is not found on the frontend, check for other common localization objects like BMI_CONF.
  4. Bypass Check: If the code validates against a hardcoded string (e.g., the literal string "BMI_OFFLINE_TOKEN"), try that as the token value directly.

5. Exploitation Strategy

Step 1: Discover the Token

Navigate to the site and extract the token from the global JS context.

  • URL: {{BASE_URL}}
  • Script: window.bmi_ajax_var.bmi_offline_token

Step 2: Trigger the Offline Backup Upload

Send the unauthenticated AJAX request.

  • Method: POST
  • URL: {{BASE_URL}}/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=bmi_initialize_offline_backup&token=[EXTRACTED_TOKEN]
    

6. Test Data Setup

  1. Install Plugin: Ensure Backup Migration <= 2.0.0 is installed and active.
  2. Configuration (Optional): To observe the "resource exhaustion" or "upload" part, configure a dummy offline/remote storage destination in the plugin settings. However, the success of the AJAX call (returning a success status or triggering the function) is sufficient for a PoC.

7. Expected Results

  • Success Response: The server returns a 200 OK response, often with a JSON body indicating the backup process or queue has started (e.g., {"success": true}).
  • Server Behavior: The server begins processing files or attempting to contact storage providers in the background.

8. Verification Steps

  1. Check Plugin Logs: If the plugin maintains internal logs (often in wp-content/uploads/backup-migration/logs/), check for entries timestamped at the time of the exploit indicating "Offline upload started" or "Queue processing triggered."
  2. Monitor Processes: Use top or ps if possible (within the environment) to see if PHP processes are consuming resources immediately after the request.
  3. WP-CLI Verification: Check the backup status/options:
    wp option get bmi_backup_status
    
    (Note: The option name bmi_backup_status is inferred from standard plugin nomenclature).

9. Alternative Approaches

If bmi_ajax_var is not visible on the frontend:

  1. Check Admin-Side (if you have any user): Even a low-privileged user might see the token if they can access the dashboard.
  2. Predictable Token: Check if the token is a predictable hash (e.g., md5(get_option('siteurl'))).
  3. Direct Action Guessing: Some versions of the plugin used the literal string BMI_OFFLINE_TOKEN as the token value in the check if none was set. Try:
    action=bmi_initialize_offline_backup&token=BMI_OFFLINE_TOKEN
    
Research Findings
Static analysis — not yet PoC-verified

Summary

The Backup Migration plugin (<= 2.0.0) contains a missing authorization vulnerability in its backup upload processing logic. Unauthenticated attackers can trigger the backup upload queue by exploiting a lack of capability checks and nonce verification on the 'bmi_initialize_offline_backup' AJAX endpoint, utilizing a token that is exposed in the site's public JavaScript.

Vulnerable Code

// Inferred registration in includes/backup-methods/offline/offline.php or initializer.php
add_action('wp_ajax_bmi_initialize_offline_backup', 'initializeOfflineAjax');
add_action('wp_ajax_nopriv_bmi_initialize_offline_backup', 'initializeOfflineAjax');

---

// Inferred localization exposing the token in localized JavaScript variables
wp_localize_script('bmi-backup-js', 'bmi_ajax_var', array(
    'bmi_offline_token' => $offline_token,
    // ...
));

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/backup-backup/2.0.0/admin/css/bmi-plugin-icon.min.css /home/deploy/wp-safety.org/data/plugin-versions/backup-backup/2.1.0/admin/css/bmi-plugin-icon.min.css
--- /home/deploy/wp-safety.org/data/plugin-versions/backup-backup/2.0.0/admin/css/bmi-plugin-icon.min.css	2025-10-30 08:28:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/backup-backup/2.1.0/admin/css/bmi-plugin-icon.min.css	2026-01-29 12:56:26.000000000 +0000
@@ -1 +1 @@
-#toplevel_page_backup-migration .wp-menu-image img{padding-top:8px !important}
+#toplevel_page_backup-migration .wp-menu-image img{padding-top:8px !important}
\ No newline at end of file
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/backup-backup/2.0.0/admin/css/bmi-plugin.min.css /home/deploy/wp-safety.org/data/plugin-versions/backup-backup/2.1.0/admin/css/bmi-plugin.min.css
--- /home/deploy/wp-safety.org/data/plugin-versions/backup-backup/2.0.0/admin/css/bmi-plugin.min.css	2025-10-30 08:28:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/backup-backup/2.1.0/admin/css/bmi-plugin.min.css	2026-01-29 12:56:26.000000000 +0000
@@ -1 +1 @@
-@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap");#bmi,#bb-warning-notice{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-family:'Montserrat', Helvetica, Arial, sans-serif;max-width:1495px;max-width:min(1495px, 95%);margin:0 auto;padding-top:55px;min-width:1495px;min-width:calc(min(1495px, 95%))} (truncated)

Exploit Outline

1. Retrieve the Offline Token: Navigate to the target website's frontend and inspect the page source or use the browser console to extract the 'bmi_offline_token' value from the 'bmi_ajax_var' global JavaScript object. 2. Formulate Request: Construct an unauthenticated POST request to the WordPress AJAX endpoint at '/wp-admin/admin-ajax.php'. 3. Payload: Include the following parameters in the request body: 'action=bmi_initialize_offline_backup' and 'token=[EXTRACTED_TOKEN]'. 4. Trigger Upload: Send the request. The server will execute the 'initializeOfflineAjax' function, triggering the backup upload process to configured remote storage without verifying if the requester has administrative privileges.

Check if your site is affected.

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