CVE-2026-3339

Keep Backup Daily <= 2.1.1 - Authenticated (Admin+) Limited Path Traversal via 'kbd_path' Parameter

lowImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
2.7
CVSS Score
2.7
CVSS Score
low
Severity
2.1.3
Patched in
1d
Time to patch

Description

The Keep Backup Daily plugin for WordPress is vulnerable to Limited Path Traversal in all versions up to, and including, 2.1.1 via the `kbd_open_upload_dir` AJAX action. This is due to insufficient validation of the `kbd_path` parameter, which is only sanitized with `sanitize_text_field()` - a function that does not strip path traversal sequences. This makes it possible for authenticated attackers, with Administrator-level access and above, to list the contents of arbitrary directories on the server outside of the intended uploads directory.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.1.1
PublishedMarch 20, 2026
Last updatedMarch 20, 2026
Affected pluginkeep-backup-daily

What Changed in the Fix

Changes introduced in v2.1.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

## Vulnerability Summary The **Keep Backup Daily** plugin for WordPress is vulnerable to **Limited Path Traversal** in versions up to and including 2.1.1. The flaw exists in the AJAX handler for the `kbd_open_upload_dir` action. The plugin accepts a user-provided directory path via the `kbd_path` p…

Show full research plan

Vulnerability Summary

The Keep Backup Daily plugin for WordPress is vulnerable to Limited Path Traversal in versions up to and including 2.1.1. The flaw exists in the AJAX handler for the kbd_open_upload_dir action. The plugin accepts a user-provided directory path via the kbd_path parameter and fails to properly validate or restrict it to the intended uploads directory.

The parameter is processed using sanitize_text_field(), which removes tags and extra whitespace but does not strip path traversal sequences like ../. As a result, an authenticated administrator can supply a path such as ../../../../ to list the contents of arbitrary directories on the server that the web server user has permissions to read.

Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: kbd_open_upload_dir (registered via wp_ajax_kbd_open_upload_dir)
  • Vulnerable Parameter: kbd_path
  • Authentication: Required (Administrator level or higher).
  • Preconditions: The attacker must be logged in as an administrator to reach the wp_ajax_ hook.
  • Vector: POST /wp-admin/admin-ajax.php with action=kbd_open_upload_dir&kbd_path=...

Code Flow

Although the specific function body for kbd_open_upload_dir is in the truncated portion of the provided source, we can reconstruct the flow based on the vulnerability description and surrounding code patterns:

  1. Hook Registration: The plugin registers the AJAX action:
    add_action('wp_ajax_kbd_open_upload_dir', 'kbd_open_upload_dir'); (inferred)
  2. Input Handling: The function kbd_open_upload_dir retrieves input:
    $path = sanitize_text_field($_POST['kbd_path']);
  3. Vulnerable Sink: The $path is passed into a directory listing function, likely scandir() or a wrapper like the plugin's own kdb_list_zipfiles($mydirectory) (found in inc/kbd_cron.php).
  4. Lack of Validation: The code fails to check if the resulting absolute path resides within wp_upload_dir().
  5. Output: The contents of the directory are returned to the user, likely as a JSON object or an HTML list.

Nonce Acquisition Strategy

The kbd_open_upload_dir action likely requires a security nonce. Based on WordPress standards and the plugin's structure, the nonce is likely localized using wp_localize_script.

Strategy:

  1. Identify the Page: The "Export" and "Settings" pages are the most likely to load the script responsible for this AJAX action.
  2. Create Setup Page: If necessary, create a post/page to trigger script loading, though since this is an Admin+ vulnerability, navigating to the plugin settings is sufficient.
  3. Navigation: Use browser_navigate to go to the plugin settings: http://localhost:8080/wp-admin/options-general.php?page=kbd_settings.
  4. Extract Nonce: Use browser_eval to find the localized object. Common identifiers for this plugin would be kbd_ajax, kbd_vars, or kbd_data.
    • Search Pattern: Look for wp_localize_script calls in the full source (not provided, but usually in register_kbd_styles).
    • Eval Command: browser_eval("window.kbd_ajax?.nonce") or browser_eval("window.kbd_data?.nonce").
  5. Fallback: If no localized nonce is found, check the HTML source for hidden inputs: jQuery('input[name="kbd_nonce"]').val().

Exploitation Strategy

Step 1: Authentication

Authenticate as a WordPress Administrator and capture cookies.

Step 2: Nonce Extraction

Navigate to the plugin settings page to extract the nonce.

  • URL: /wp-admin/options-general.php?page=kbd_settings
  • Method: browser_navigate followed by browser_eval.

Step 3: Traversal Request

Send a crafted AJAX request to list the root directory.

  • Request Tool: http_request
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=kbd_open_upload_dir&kbd_path=../../../../&security=[NONCE]
    
    (Note: The nonce parameter name security is a common default; replace with the actual key found in Step 2).

Step 4: Verification

The response should contain a listing of the server's root directory (e.g., bin, etc, home, var).

Test Data Setup

  1. User: Create an administrator user.
    • wp user create attacker admin@example.com --role=administrator --user_pass=password
  2. Plugin Activation: Ensure "Keep Backup Daily" is active.
    • wp plugin activate keep-backup-daily
  3. Settings Initialization: Visit the settings page once to ensure any default options/paths are generated.
    • browser_navigate("http://localhost:8080/wp-admin/options-general.php?page=kbd_settings")

Expected Results

A successful exploit will return a directory listing of the path specified in kbd_path.

Example Vulnerable Response (JSON):

{
  "success": true,
  "data": [
    ".",
    "..",
    "etc",
    "home",
    "root",
    "var",
    "wp-config.php"
  ]
}

If the plugin returns HTML, look for <li> or <a> tags containing file names from the traversal target.

Verification Steps

  1. Examine Response: Verify that the http_request response body contains directory entries that are clearly from the filesystem root (e.g., /etc, /var) or the WordPress root (if traversed only that far).
  2. Filesystem Match: Compare the output with the actual filesystem contents using WP-CLI:
    • wp eval "print_r(scandir('/'));"
  3. Confirm Path: If the response shows the contents of /etc, the traversal is confirmed.

Alternative Approaches

  • Blind Traversal: If the output is not directly returned, attempt to trigger an error by providing an invalid path or a path that exists but is inaccessible, and check for differences in response time or status codes.
  • Different Traversal Sinks: Check if kbd_path is used in other actions, such as a file deletion or download action (e.g., kbd_force_download in inc/functions.php). If kbd_force_download uses a path parameter without validation, it could lead to Arbitrary File Download (AFD).
  • Check kbd_download: The function kbd_download() in inc/functions.php calls kbd_force_download(). Investigate if kbd_force_download accepts a file path via $_GET['file'] (referenced in truncated inc/kbd_cron.php) that might also be vulnerable to traversal.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Keep Backup Daily plugin is vulnerable to limited path traversal through the 'kbd_path' parameter in its AJAX handlers. Authenticated administrators can bypass directory restrictions to list the contents of arbitrary directories on the server because the input is only processed with basic text sanitization that fails to block traversal sequences like '../'.

Vulnerable Code

// From inc/functions.php (approx. line 834 in version 2.1.2)
$kbd_path = sanitize_kbd_data($_POST['kbd_path']);
$kbd_path= str_replace('\\', '/', $kbd_path);
$kbd_path= str_replace('\\', '/', $kbd_path);

kbd_get_dir_list_html($kbd_path, 'sub');

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/keep-backup-daily/2.1.2/inc/functions.php /home/deploy/wp-safety.org/data/plugin-versions/keep-backup-daily/2.1.3/inc/functions.php
--- /home/deploy/wp-safety.org/data/plugin-versions/keep-backup-daily/2.1.2/inc/functions.php	2026-02-28 07:14:48.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/keep-backup-daily/2.1.3/inc/functions.php	2026-03-13 00:17:58.000000000 +0000
@@ -578,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']!=''){
@@ -834,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');

Exploit Outline

The exploit requires an authenticated WordPress user with Administrator privileges. 1. Login to the WordPress admin panel. 2. Access the plugin settings page (usually under Settings > Keep Backup Daily) to extract a valid security nonce and verify the plugin's AJAX structure. 3. Send a POST request to /wp-admin/admin-ajax.php using the action 'kbd_open_upload_dir'. 4. In the request body, provide the 'kbd_path' parameter containing a directory traversal payload, such as '../../../../'. 5. The server response will contain a directory listing of the target path (e.g., the server root or WordPress root directory), allowing the attacker to discover sensitive file names and system structure.

Check if your site is affected.

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