Backup and Staging by WP Time Capsule <= 1.22.26 - Missing Authorization to Authenticated (Subscriber+) Sensitive Information Exposure via download_recent_decrypted_file_wptc Function
Description
The Backup and Staging by WP Time Capsule plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 1.22.26 via the download_recent_decrypted_file_wptc. This makes it possible for authenticated attackers, with subscriber-level access and above, to extract download the most recently admin-decrypted SQL database backup, which typically contains password hashes, user credentials, and other sensitive site configuration data stored in the 'recent_decrypted_file' option. Exploitation requires that an administrator has previously performed a decrypt action, causing the decrypted SQL backup file to exist in the plugin's upload directory; without this prior admin action, there is no file to serve.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=1.22.26What Changed in the Fix
Changes introduced in v1.22.27
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-8996 ## 1. Vulnerability Summary The **Backup and Staging by WP Time Capsule** plugin (up to version 1.22.26) is vulnerable to **Sensitive Information Exposure**. The plugin implements an AJAX handler `download_recent_decrypted_file_wptc` which is intended to …
Show full research plan
Exploitation Research Plan: CVE-2026-8996
1. Vulnerability Summary
The Backup and Staging by WP Time Capsule plugin (up to version 1.22.26) is vulnerable to Sensitive Information Exposure. The plugin implements an AJAX handler download_recent_decrypted_file_wptc which is intended to allow administrators to download SQL database backups after they have been decrypted for restoration or cloning. However, the function fails to perform adequate authorization checks (e.g., current_user_can('manage_options')). Consequently, any authenticated user with Subscriber-level permissions or higher can trigger this function to download the most recently decrypted SQL backup, which contains sensitive information including WordPress user password hashes, site configuration, and database structure.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
download_recent_decrypted_file_wptc - Method:
GETorPOST(WordPress AJAX handlers typically support both, but the name implies a download/GET context). - Authentication: Authenticated (Subscriber-level or higher).
- Vulnerable Parameter: The
actionparameter triggers the code; the file path is retrieved internally from the database optionrecent_decrypted_file. - Precondition: An administrator must have previously used the "Decrypt" feature on an encrypted database backup. This action populates the
recent_decrypted_fileoption and ensures the decrypted file exists in the plugin's temporary storage directory.
3. Code Flow
- Entry Point: The request is sent to
admin-ajax.phpwithaction=download_recent_decrypted_file_wptc. - Hook Registration: The plugin registers the action (likely in
Classes/WptcBackup/HooksHandler.phporClasses/Common/HooksHandler.php- inferred):add_action('wp_ajax_download_recent_decrypted_file_wptc', 'download_recent_decrypted_file_wptc'); - Vulnerable Function Execution: The function
download_recent_decrypted_file_wptcis called. - Option Retrieval: The code calls
get_option('recent_decrypted_file')to retrieve the absolute path of the most recently decrypted SQL file. - Information Exposure (Sink): The function uses
readfile()or similar file output functions to send the contents of the SQL file to the user's browser without checking if the current user has themanage_optionscapability.
4. Nonce Acquisition Strategy
The WP Time Capsule plugin typically localizes its AJAX settings and nonces into a JavaScript object. To find the correct nonce:
- Identify Script Localization: The plugin usually enqueues scripts on its admin pages. We can find the nonce by creating a page that loads the plugin context or by accessing a default admin dashboard as a subscriber (where some WPTC scripts may still load).
- Create Trigger Content: If the script only loads on specific pages, we can use WP-CLI to create a page with a WPTC-related shortcode if any exist (e.g.,
[wptc_test]). - Browser Extraction:
- Navigate to the WordPress dashboard (
/wp-admin/index.php) as a Subscriber. - Use
browser_evalto search for the WPTC AJAX object. - Common Variable Name:
window.wptc_ajax_object(inferred from common plugin patterns). - Common Nonce Key:
window.wptc_ajax_object.nonce.
- Navigate to the WordPress dashboard (
- Check for Nonce Enforcement: If
download_recent_decrypted_file_wptcwas designed for direct file download, it might lack a nonce check entirely, as the primary vulnerability is the missing authorization.
5. Exploitation Strategy
- Pre-Exploit Setup (Internal Site): As an admin, run a backup and use the "Decrypt DB" feature to ensure the
recent_decrypted_fileoption is set. - Authentication: Obtain session cookies for a user with
Subscriberrole. - Discovery: Retrieve the nonce if required (see Section 4).
- Execution: Use the
http_requesttool to perform a GET request to the AJAX endpoint.- URL:
https://[target]/wp-admin/admin-ajax.php?action=download_recent_decrypted_file_wptc - Headers: Include
Cookie: [subscriber_cookies]
- URL:
- Payload Extraction: If successful, the response body will contain a raw SQL dump of the WordPress database.
6. Test Data Setup
To verify the vulnerability, the environment must be prepared:
- Install Plugin: Install version 1.22.26 of Backup and Staging by WP Time Capsule.
- Create Users:
- Admin:
admin_user/password - Subscriber:
attacker_sub/password
- Admin:
- Configure Plugin: As Admin, connect a cloud storage (or use local/staging mode) and perform at least one backup with Database Encryption enabled.
- Trigger Decryption: In the WPTC dashboard, find the database backup and select the "Decrypt" option. This will place a file in
wp-content/uploads/tCapsule/backups/.../filename.sql. - Confirm Option: Use WP-CLI to verify the path is stored:
wp option get recent_decrypted_file
7. Expected Results
- Successful Exploitation: The
http_requestreturns a200 OKstatus, and the response body begins with SQL dump headers (e.g.,INSERT INTO wp_users ...or-- WordPress MySQL dump). - Failed Exploitation (Patched): The response is
403 Forbiddenor0(WordPress default for unauthorized AJAX).
8. Verification Steps
After the HTTP request, confirm the data is valid:
- Inspect Response: Check the response body for the string
wp_users. - Check for Password Hashes: Verify that the output contains the password hash of the admin user (e.g., strings starting with
$P$B). - WP-CLI Verification: Confirm the file downloaded matches the one stored in the path found via
wp option get recent_decrypted_file.
9. Alternative Approaches
- Path Traversal Check: If the function accepts a filename parameter (e.g.,
?file=...), check if it's vulnerable to path traversal (e.g.,../../../../wp-config.php). Based on the CVE, the path is likely hardcoded to the option value, but this should be checked. - Direct Access: Check if the decrypted file path (retrieved from the option via WP-CLI for testing) is directly accessible via a URL (e.g.,
https://[target]/wp-content/uploads/tCapsule/backups/.../dump.sql). The plugin should ideally use an.htaccessorindex.htmlto block this, but the AJAX handler provides a direct bypass.
Summary
The Backup and Staging by WP Time Capsule plugin for WordPress is vulnerable to Sensitive Information Exposure via the `download_recent_decrypted_file_wptc` function. Due to missing authorization and nonce checks, authenticated attackers with subscriber-level access or higher can download the site's most recently decrypted SQL database backup, provided an administrator has recently performed a decryption action.
Vulnerable Code
// wp-time-capsule.php L3767 function download_recent_decrypted_file_wptc(){ if ( !is_admin() ) { return ; } $wptc_file_path = WPTC_Factory::get('config')->get_option('recent_decrypted_file'); wptc_log($wptc_file_path,'-----------$wptc_file_path----------------');
Security Fix
@@ -3687,7 +3687,9 @@ WPTC_Factory::get('config')->set_option('recent_decrypted_file', $result['fullpath']); - $result['message'] = "Decryption Completed. <a href=" . network_admin_url() . "?page=wp-time-capsule-settings&download=1#wp-time-capsule-tab-advanced>Download your file here</a>. After downloaded <a href='#' id='wptc-clear-all-decrypt-files'>click here</a> to delete the file for security reason."; + $wptc_download_decrypt_nonce = wp_create_nonce( 'download_decrypt' ); + + $result['message'] = "Decryption Completed. <a href=" . network_admin_url() . "?page=wp-time-capsule-settings&download=1&wptc_download_decrypt_nonce=" . $wptc_download_decrypt_nonce . "#wp-time-capsule-tab-advanced>Download your file here</a>. After downloaded <a href='#' id='wptc-clear-all-decrypt-files'>click here</a> to delete the file for security reason."; wptc_die_with_json_encode($result); } @@ -3767,6 +3769,14 @@ return ; } + if (! isset( $_GET['wptc_download_decrypt_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['wptc_download_decrypt_nonce'] ) ), 'download_decrypt' ) ) { + return; + } + + if(!is_user_logged_in() || !current_user_can('manage_options')){ + return; + } + $wptc_file_path = WPTC_Factory::get('config')->get_option('recent_decrypted_file'); wptc_log($wptc_file_path,'-----------$wptc_file_path----------------');
Exploit Outline
The exploit targets the AJAX action 'download_recent_decrypted_file_wptc'. An attacker needs authenticated access (Subscriber level or higher) and must send a request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'download_recent_decrypted_file_wptc'. The vulnerability exists because the function only checks is_admin(), which is always true for AJAX requests, and fails to check user capabilities (current_user_can) or nonces. If an administrator has recently used the plugin's decryption tool, the plugin will serve the decrypted SQL database backup file stored in the 'recent_decrypted_file' option directly to the attacker.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.