CVE-2026-4031

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

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 authorization bypass in all versions up to, and including, 2.5.2. This is due to the plugin not restricting access to the wp_db_temp_dir parameter, which controls where database backups are written. This makes it possible for unauthenticated attackers to send a request to wp-cron.php with a poisoned wp_db_temp_dir value pointing to a publicly accessible directory (e.g., wp-content/uploads/), and if a scheduled backup is due, intercept the backup file before it is cleaned up. The backup file has a predictable name based on the database name, table prefix, date, and Swatch Internet Time, making interception reliable. Successful exploitation leads to Sensitive Information Exposure including database credentials, user password hashes, and personally identifiable information. This vulnerability requires that the site administrator has configured scheduled backups.

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

This research plan outlines the steps to verify and exploit **CVE-2026-4031**, a missing authorization vulnerability in the **Database Backup for WordPress** plugin. ### 1. Vulnerability Summary The `wp-db-backup` plugin (up to version 2.5.2) allows unauthenticated users to influence the directory …

Show full research plan

This research plan outlines the steps to verify and exploit CVE-2026-4031, a missing authorization vulnerability in the Database Backup for WordPress plugin.

1. Vulnerability Summary

The wp-db-backup plugin (up to version 2.5.2) allows unauthenticated users to influence the directory where scheduled database backups are temporarily stored. This occurs because the plugin's constructor in wp-db-backup.php reads the wp_db_temp_dir parameter from the global $_GET array without performing any capability or authentication checks. If an attacker provides a path to a publicly accessible directory (like wp-content/uploads/), a scheduled backup triggered via wp-cron.php will be written to that location. Because the backup filename is predictable, the attacker can then download the entire database dump.

2. Attack Vector Analysis

  • Target Endpoint: [WP_URL]/wp-cron.php
  • Vulnerable Parameter: wp_db_temp_dir (passed via GET)
  • Authentication: None (Unauthenticated)
  • Preconditions:
    1. The site administrator must have configured a "Scheduled Backup" (found in Tools > Backup).
    2. The attacker must know or guess the absolute path to a writable, public directory (e.g., /var/www/html/wp-content/uploads/).
    3. A scheduled backup must be due for execution when the attacker triggers wp-cron.php.

3. Code Flow

  1. Entry Point: A request is made to any WordPress page (specifically wp-cron.php) with ?wp_db_temp_dir=/path/to/public/dir.
  2. Initialization: The wpdbBackup class is instantiated. In the constructor (wp-db-backup.php line 135):
    $tmp_dir = get_temp_dir();
    
    if ( isset( $_GET['wp_db_temp_dir'] ) ) {
        $requested_dir = sanitize_text_field( $_GET['wp_db_temp_dir'] );
        if ( is_writeable( $requested_dir ) ) { // No auth check here!
            $tmp_dir = $requested_dir;
        }
    }
    $this->backup_dir = trailingslashit( apply_filters( 'wp_db_b_backup_dir', $tmp_dir ) );
    
  3. Cron Trigger: wp-cron.php checks for pending tasks. If wp_db_backup_cron is due, it fires.
  4. Backup Execution: The cron_backup() method (hooked at line 115) runs. It uses $this->backup_dir to store the generated SQL file.
  5. Filename Generation: The filename is generated in the constructor (lines 124-125):
    $datum                 = date( 'Ymd_B' );
    $this->backup_filename = DB_NAME . "_$table_prefix$datum.sql";
    
    • DB_NAME: Database name (e.g., wordpress).
    • $table_prefix: WordPress table prefix (e.g., wp_).
    • date('Ymd_B'): Ymd is the date, B is the Swatch Internet Time (000-999).

4. Nonce Acquisition Strategy

This specific vulnerability does not require a nonce.
The poisoned parameter is processed in the class constructor (__construct), which runs on every request including unauthenticated cron triggers. While the "Scheduled Backup" form was patched with a nonce in 2.5.2 to prevent CSRF, the consumption of the wp_db_temp_dir parameter in the constructor remains unauthenticated in affected versions.

5. Exploitation Strategy

Step 1: Reconnaissance

Identify the database name and table prefix.

  • Standard defaults are DB_NAME=wordpress and $table_prefix=wp_.
  • Determine the current Swatch Internet Time (date('B')).

Step 2: Poison the Backup Path & Trigger Cron

Send a request to wp-cron.php supplying the poisoned directory and triggering the cron runner.

  • Request: GET /wp-cron.php?doing_wp_cron&wp_db_temp_dir=/var/www/html/wp-content/uploads/
  • Note: The absolute path is required. In standard Docker environments, this is usually /var/www/html/wp-content/uploads/.

Step 3: Predict the Filename

The file will be named: [DB_NAME]_[PREFIX][YYYYMMDD]_[SWATCH_TIME].sql.
Example: wordpress_wp_20231027_123.sql.

  • Since Swatch time represents "beats" (1000 per day), you may need to check the current beat and the next 2-3 beats to account for execution time.

Step 4: Intercept the Backup

Immediately attempt to download the file from the public uploads directory.

  • Request: GET /wp-content/uploads/wordpress_wp_20231027_123.sql

6. Test Data Setup

  1. Plugin Installation: Install and activate wp-db-backup version 2.5.2.
  2. Configuration:
    • Navigate to Tools > Backup.
    • Under "Scheduled Backup", select "Once Daily" and enter an email address.
    • Click "Save Settings".
  3. Cron Sync: Ensure a backup task is actually scheduled:
    wp cron event list --name=wp_db_backup_cron
    
  4. Force Due: To make the exploit reliable for testing, set the next run time to the past:
    wp cron event run wp_db_backup_cron --due-now
    

7. Expected Results

  • The request to wp-cron.php should return a 200 OK (empty response).
  • A file should appear in wp-content/uploads/ containing the full MySQL database export.
  • The content of the SQL file will include the wp_users table with admin password hashes and the wp_options table.

8. Verification Steps

  1. Verify File Creation: Use ls inside the environment to check if the file exists in the uploads directory:
    ls -la /var/www/html/wp-content/uploads/*.sql
    
  2. Verify Content: Check the head of the SQL file for database structure:
    head /var/www/html/wp-content/uploads/[FILENAME].sql
    

9. Alternative Approaches

  • Swatch Brute-force: If the exact time of the cron execution is slightly off, iterate through 10 beats (approx. 14 minutes) of Swatch time filenames.
  • Directory Listing: If the server has directory listing enabled on wp-content/uploads/, simply navigate to that URL to see the generated file.
  • Path Discovery: If /var/www/html/ is incorrect, common WordPress paths include /home/user/public_html/wp-content/uploads/ or using the is_writeable check to confirm paths via error-based side channels if WP_DEBUG is on.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Database Backup for WordPress plugin allows unauthenticated users to specify the directory where scheduled database backups are temporarily stored via the 'wp_db_temp_dir' parameter. By pointing this to a publicly accessible directory, an attacker can intercept and download the resulting database dump, which uses a predictable filename based on the database name, prefix, and current time.

Vulnerable Code

// wp-db-backup.php lines 120-121
$datum                 = date( 'Ymd_B' );
$this->backup_filename = DB_NAME . "_$table_prefix$datum.sql";

---

// wp-db-backup.php lines 146-153
$tmp_dir = get_temp_dir();

if ( isset( $_GET['wp_db_temp_dir'] ) ) {
	$requested_dir = sanitize_text_field( $_GET['wp_db_temp_dir'] );
	if ( is_writeable( $requested_dir ) ) {
		$tmp_dir = $requested_dir;
	}
}

Security Fix

--- wp-db-backup.php
+++ wp-db-backup.php
@@ -146,9 +146,2 @@
 		$tmp_dir = get_temp_dir();
 
-		if ( isset( $_GET['wp_db_temp_dir'] ) ) {
-			$requested_dir = sanitize_text_field( $_GET['wp_db_temp_dir'] );
-			if ( is_writeable( $requested_dir ) ) {
-				$tmp_dir = $requested_dir;
-			}
-		}
-

Exploit Outline

1. Identify a writeable, publicly accessible directory on the target server (e.g., /var/www/html/wp-content/uploads/). 2. Determine the target's database name and table prefix (defaults: 'wordpress', 'wp_'). 3. Send an unauthenticated GET request to wp-cron.php with the poisoned parameter: ?doing_wp_cron&wp_db_temp_dir=[absolute_path_to_public_dir]. 4. Trigger the WordPress cron system. If a scheduled backup task is due, the plugin will save the SQL dump to the specified public directory. 5. Predict the backup filename (DBNAME_PREFIX_YYYYMMDD_SWATCHTIME.sql) and download the file from the public directory.

Check if your site is affected.

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