Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 15, 2026

CVE-2026-4029: Database Backup for WordPress <= 2.5.2 – Missing Authorization to Unauthenticated Database Export (wp-db-backup)

CVE ID CVE-2026-4029
Plugin wp-db-backup
Severity High (CVSS 7.5)
CWE 862
Vulnerable Version 2.5.2
Patched Version 2.5.3
Disclosed May 12, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-4029: The Database Backup for WordPress plugin can_user_backup() without checking its return value in two locations: when $_GET[‘fragment’] is set (line 151) and when $_GET[‘backup’] is set (line 155). The can_user_backup() function itself (line 1647-1654) contains a check using the deprecated is_site_admin() function that returns false for unauthorized users, but the callers in the admin_init hook never evaluate this return value to halt execution. Additionally, the backup filename construction at line 100-103 generated predictable filenames without nonce randomization.

Exploitation: An unauthenticated attacker can directly access the plugin’s page (wp-admin/edit.php?page=wp-db-backup) with the backup parameter set to trigger a database export. The attack vector requires a WordPress Multisite installation. The attacker sends an HTTP GET request to the vulnerable endpoint (e.g., /wp-admin/edit.php?page=wp-db-backup&backup=1). The plugin’s admin_init handler (line 155) calls can_user_backup() but ignores the false return value, then proceeds to execute the backup routine at line 160, dumping database contents to a predictable file path.

Patch Analysis: The patch adds explicit return checks after both can_user_backup() calls at lines 148-160. If can_user_backup() returns false, execution halts via ‘return’. The patch also randomizes backup filenames by adding a 12-character nonce via wp_generate_password() at line 102, preventing predictable filename guessing. Additional hardening includes changing class variables from public to private, removing the wp_db_temp_dir directory injection vector (lines 125-129 deleted), and adding an error message in can_user_backup() at line 1630-1640.

Impact: Successful exploitation allows unauthenticated attackers to export the entire WordPress database, exposing sensitive information including user credentials (hashed passwords, email addresses), session tokens, configuration data, and private content. This can lead to complete site compromise if attackers can crack password hashes or leverage exposed session data.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/wp-db-backup/wp-db-backup.php
+++ b/wp-db-backup/wp-db-backup.php
@@ -5,7 +5,7 @@
 Description: On-demand backup of your WordPress database. Navigate to <a href="edit.php?page=wp-db-backup">Tools → Backup</a> to get started.
 Author: Delicious Brains
 Author URI: https://deliciousbrains.com
-Version: 2.5.2
+Version: 2.5.3
 Domain Path: /languages

 This program is free software; you can redistribute it and/or modify
@@ -43,15 +43,17 @@

 class wpdbBackup {

-	var $backup_complete = false;
-	var $backup_file     = '';
-	var $backup_filename;
-	var $core_table_names = array();
-	var $errors           = array();
-	var $basename;
-	var $page_url;
-	var $referer_check_key;
-	var $version = '2.5.2';
+	private $backup_complete = false;
+	private $backup_file     = '';
+	private $backup_filename;
+	private $core_table_names = array();
+	private $errors           = array();
+	private $backup_dir;
+	private $basename;
+	private $fp;
+	private $page_url;
+	private $referer_check_key;
+	private $version = '2.5.3';

 	function module_check() {
 		$mod_evasive = false;
@@ -87,9 +89,11 @@
 		add_filter( 'cron_schedules', array( &$this, 'add_sched_options' ) );
 		add_filter( 'wp_db_b_schedule_choices', array( &$this, 'schedule_choices' ) );

-		$table_prefix          = ( isset( $table_prefix ) ) ? $table_prefix : $wpdb->prefix;
-		$datum                 = date( 'Ymd_B' );
-		$this->backup_filename = DB_NAME . "_$table_prefix$datum.sql";
+		$table_prefix = ( isset( $table_prefix ) ) ? $table_prefix : $wpdb->prefix;
+		$datum        = date( 'Ymd_B' );
+		$nonce        = wp_generate_password( 12, false );
+
+		$this->backup_filename = sanitize_text_field( DB_NAME . '_' . $table_prefix . $datum . '_' . $nonce . '.sql' );

 		$possible_names = array(
 			'categories',
@@ -118,13 +122,6 @@

 		$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;
-			}
-		}
-
 		$this->backup_dir = trailingslashit( apply_filters( 'wp_db_b_backup_dir', $tmp_dir ) );
 		$this->basename   = 'wp-db-backup';

@@ -151,10 +148,14 @@
 					break;
 			}
 		} elseif ( isset( $_GET['fragment'] ) ) {
-			$this->can_user_backup( 'frame' );
+			if ( ! $this->can_user_backup( 'frame' ) ) {
+				return;
+			}
 			add_action( 'init', array( &$this, 'init' ) );
 		} elseif ( isset( $_GET['backup'] ) ) {
-			$this->can_user_backup();
+			if ( ! $this->can_user_backup() ) {
+				return;
+			}
 			add_action( 'init', array( &$this, 'init' ) );
 		} else {
 			add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
@@ -314,7 +315,7 @@

 			function backup(table, segment) {
 				var fram = document.getElementById("backuploader");
-				fram.src = "' . $this->page_url . '&fragment=" + table + ":" + segment + ":' . $this->backup_filename . ':&wp_db_temp_dir=' . $this->backup_dir . '";
+				fram.src = "' . $this->page_url . '&fragment=" + table + ":" + segment + ":' . $this->backup_filename . ':";
 			}

 			var curStep = 0;
@@ -421,7 +422,7 @@
 			}
 		}

-		if ( is_writable( $this->backup_dir ) ) {
+		if ( wp_is_writable( $this->backup_dir ) ) {
 			$this->fp = $this->open( $this->backup_dir . $filename, 'a' );
 			if ( ! $this->fp ) {
 				$this->error( __( 'Could not open the backup file for writing!', 'wp-db-backup' ) );
@@ -691,6 +692,10 @@
 	 * Taken from phpMyAdmin.
 	 */
 	function sql_addslashes( $a_string = '', $is_like = false ) {
+		if ( empty( $a_string ) ) {
+			return $a_string;
+		}
+
 		if ( $is_like ) {
 			$a_string = str_replace( '\', '\\\\', $a_string );
 		} else {
@@ -933,6 +938,8 @@
 								// yet try to avoid quotation marks around integers
 								$value    = ( null === $value || '' === $value ) ? $defs[ strtolower( $key ) ] : $value;
 								$values[] = ( '' === $value ) ? "''" : $value;
+							} elseif ( empty( $value ) ) {
+								$values[] = "'" . $value . "'";
 							} else {
 								$values[] = "'" . str_replace( $search, $replace, $this->sql_addslashes( $value ) ) . "'";
 							}
@@ -957,7 +964,7 @@
 	function db_backup( $core_tables, $other_tables ) {
 		global $table_prefix, $wpdb;

-		if ( is_writable( $this->backup_dir ) ) {
+		if ( wp_is_writable( $this->backup_dir ) ) {
 			$this->fp = $this->open( $this->backup_dir . $this->backup_filename );
 			if ( ! $this->fp ) {
 				$this->error( __( 'Could not open the backup file for writing!', 'wp-db-backup' ) );
@@ -1096,8 +1103,18 @@
 				$recipient = get_option( 'admin_email' );
 			}

-			$message = sprintf( __( "Attached to this email isn   %1$1sn   Size:%2$2s kilobytesn", 'wp-db-backup' ), $filename, round( filesize( $file_to_deliver ) / 1024 ) );
-			$success = $this->send_mail( $recipient, get_bloginfo( 'name' ) . ' ' . __( 'Database Backup', 'wp-db-backup' ), $message, $file_to_deliver );
+			$message   = sprintf(
+				__( "Attached to this email isn   %1$1sn   Size:%2$2s kilobytesn", 'wp-db-backup' ),
+				$filename,
+				round( filesize( $file_to_deliver ) / 1024 )
+			);
+			$blog_name = sanitize_text_field( html_entity_decode( get_bloginfo( 'name' ) ) );
+			$success   = $this->send_mail(
+				$recipient,
+				$blog_name . ' ' . __( 'Database Backup', 'wp-db-backup' ),
+				$message,
+				$file_to_deliver
+			);

 			if ( false === $success ) {
 				$msg = __( 'The following errors were reported:', 'wp-db-backup' ) . "n ";
@@ -1219,7 +1236,7 @@
 			<?php
 			// not writable due to write permissions
 			$whoops = true;
-		} elseif ( ! is_writable( $this->backup_dir ) && ! @chmod( $this->backup_dir, $dir_perms ) ) {
+		} elseif ( ! wp_is_writable( $this->backup_dir ) && ! @chmod( $this->backup_dir, $dir_perms ) ) {
 			?>
 			<div class="wp-db-backup-updated error inline">
 				<p><?php _e( 'WARNING: Your backup directory is <strong>NOT</strong> writable! We cannot create the backup files.', 'wp-db-backup' ); ?></p>
@@ -1630,6 +1647,16 @@

 		// make sure WPMU users are site admins, not ordinary admins
 		if ( function_exists( 'is_site_admin' ) && ! is_site_admin() ) {
+			$this->error(
+				array(
+					'loc'  => $loc,
+					'kind' => 'fatal',
+					'msg'  => __(
+						'You are not allowed to perform backups.',
+						'wp-db-backup'
+					),
+				)
+			);
 			return false;
 		}

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School