CVE-2026-4029

Database Backup for WordPress <= 2.5.2 - Missing Authorization to Unauthenticated Database Export

highMissing Authorization
7.5
CVSS Score
7.5
CVSS Score
high
Severity
2.5.3
Patched in
2d
Time to patch

Description

The Database Backup for WordPress plugin for WordPress is vulnerable to unauthorized database export in all versions up to, and including, 2.5.2. This is due to the plugin not properly enforcing the return value of its authorization check. This makes it possible for unauthenticated attackers to export database tables, leading to Sensitive Information Exposure. Note: This vulnerability is only exploitable in WordPress Multisite environments where the deprecated is_site_admin() function exists.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.5.2
PublishedMay 13, 2026
Last updatedMay 14, 2026
Affected pluginwp-db-backup

What Changed in the Fix

Changes introduced in v2.5.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-4029 ## 1. Vulnerability Summary The **Database Backup for WordPress** plugin (<= 2.5.2) contains a missing authorization vulnerability that allows unauthenticated attackers to trigger and download a full database export. The flaw exists because the plugin's …

Show full research plan

Exploitation Research Plan - CVE-2026-4029

1. Vulnerability Summary

The Database Backup for WordPress plugin (<= 2.5.2) contains a missing authorization vulnerability that allows unauthenticated attackers to trigger and download a full database export. The flaw exists because the plugin's authorization method, can_user_backup(), fails to terminate execution (e.g., via wp_die()) when an authorization check fails, particularly in WordPress Multisite environments where the legacy is_site_admin() function is present.

Because the caller of this function (the init() method) does not check the return value of can_user_backup(), the code proceeds to execute the backup and delivery logic regardless of the user's authentication or authorization status.

2. Attack Vector Analysis

  • Endpoints: Any WordPress page (frontend or backend), as the vulnerable logic is hooked to init.
  • Vulnerable Parameters: fragment (for triggering the export) and backup (for downloading the file).
  • Authentication: None required (Unauthenticated).
  • Preconditions:
    1. The environment must be a WordPress Multisite installation.
    2. The deprecated function is_site_admin() must exist in the environment (common in legacy Multisite setups or installations with compatibility layers).

3. Code Flow

  1. Entry Point: An unauthenticated request is made with the fragment GET parameter.
  2. Hook Registration: Inside wp-db-backup.php, the __construct() method of the wpdbBackup class runs:
    } elseif ( isset( $_GET['fragment'] ) ) {
        $this->can_user_backup( 'frame' ); // Logic fails to die() here
        add_action( 'init', array( &$this, 'init' ) );
    
  3. Authorization Failure: can_user_backup() is called. In a Multisite environment with is_site_admin() defined, the plugin checks authorization but likely returns false instead of calling wp_die().
  4. Bypass: The execution returns to __construct(), which successfully registers the init action.
  5. Execution Sink: When the init hook fires, wpdbBackup::init() is called:
    function init() {
        $this->can_user_backup(); // Again, return value ignored
        if ( isset( $_GET['fragment'] ) ) {
            list($table, $segment, $filename) = explode( ':', sanitize_text_field( $_GET['fragment'] ) );
            // ... validation logic ...
            $this->backup_fragment( $table, $segment, $filename ); // Table is dumped to file
        }
    }
    
  6. Retrieval: The attacker then makes a second request with ?backup=[filename] to download the generated file via deliver_backup().

4. Nonce Acquisition Strategy

This vulnerability bypasses nonce checks entirely.

  • The do_backup POST path in __construct is protected by check_admin_referer( $this->referer_check_key ).
  • However, the fragment and backup GET paths used for the fragment-based backup process do not verify nonces in the vulnerable versions.
  • Conclusion: No nonce is required for this exploit.

5. Exploitation Strategy

Step 1: Trigger Table Export

Identify the target table (usually the users table, including the prefix, e.g., wp_users). We will use a custom filename to avoid collision with the Swatch-time-based default filenames.

Request:

  • Method: GET
  • URL: http://<target>/index.php?fragment=wp_users:0:pwned_db.sql

The plugin will execute backup_fragment('wp_users', 0, 'pwned_db.sql'), writing the first segment of the users table to the backup directory.

Step 2: Download the Export

Once the file is generated, request it using the backup parameter.

Request:

  • Method: GET
  • URL: http://<target>/index.php?backup=pwned_db.sql&via=http

The plugin will call deliver_backup('pwned_db.sql', 'http'), which sends the SQL file content in the HTTP response.

6. Test Data Setup

  1. Multisite Setup: Convert the test WordPress instance to a Multisite network (add define('WP_ALLOW_MULTISITE', true); to wp-config.php and follow the Network Setup).
  2. Mock Deprecated Function: Since is_site_admin() was removed in WP 3.0, ensure it is available to satisfy the exploit condition:
    • wp eval 'function is_site_admin() { return false; }' --skip-plugins (Or add this function to a custom mu-plugin).
  3. Plugin Configuration: Install and activate wp-db-backup version 2.5.2.
  4. Target Data: Create several dummy users to verify they appear in the export.

7. Expected Results

  • First Request: Should return a 200 OK (often with minimal output or a script tag).
  • Second Request: The response headers should include Content-Type: application/octet-stream (or similar) and Content-Disposition: attachment; filename="pwned_db.sql".
  • Content: The body of the response should contain valid SQL dump syntax (e.g., INSERT INTO "wp_users" ...).

8. Verification Steps

  1. Check for generated file: After Step 1, use WP-CLI to verify the file exists in the temporary backup directory:
    wp eval 'echo get_temp_dir();'
    Search that directory for pwned_db.sql.
  2. Inspect Response: Verify the downloaded SQL contains sensitive data such as user login names and hashed passwords.

9. Alternative Approaches

  • Automated Full Export: If fragment requires iterating segments, a script can be written to loop through segment values (0, 1, 2...) until the table is fully dumped.
  • Core Tables Guessing: If the table prefix is unknown, attempt to guess common ones (wp_, wp_1_, wp_2_) or try to dump wp_options first to find the prefix.
  • Temporary Directory Traversal: If validate_file is weak (not visible in snippet), try to use the backup parameter to read other system files, though the plugin primarily restricts this to $this->backup_dir.

Check if your site is affected.

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