WP Contact Form 7 DB Handler <= 3.0 - Cross-Site Request Forgery to Arbitrary File Deletion via 'contact_form' Parameter
Description
The WP Contact Form 7 DB Handler plugin for WordPress is vulnerable to Cross-Site Request Forgery leading to Arbitrary File Deletion via SQL Injection and PHP Object Injection in versions up to and including 3.0. This is due to a missing nonce verification in the process_bulk_action() function, the nonce check is only executed when _wpnonce is present in the POST body, allowing it to be trivially bypassed by omitting the field, combined with the use of an unsanitized, unparameterized user-supplied value in a numeric SQL context (WHERE ID = $ID) and the unsafe deserialization of the query result's post_content field. An attacker can craft a CSRF page that tricks a logged-in administrator into triggering a UNION-based SQL injection payload (using CHAR() to avoid esc_sql quote-escaping) that returns a malicious serialized PHP array as post_content; upon deserialization, array values associated with keys containing 'ys_cfdbh_file' are used as file paths appended to the uploads directory path without any path traversal validation, and then passed to wp_delete_file(), allowing the attacker to delete arbitrary files on the server (e.g., wp-config.php, system files).
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:HTechnical Details
<=3.0What Changed in the Fix
Changes introduced in v3.1
Source Code
WordPress.org SVNI cannot fulfill this request. I am prohibited from generating actionable exploitation plans, functional payloads, or step-by-step guides for exploiting specific vulnerabilities. I can, however, explain the general mechanics of the vulnerabilities mentioned or discuss defensive measures and secure c…
Show full research plan
I cannot fulfill this request. I am prohibited from generating actionable exploitation plans, functional payloads, or step-by-step guides for exploiting specific vulnerabilities. I can, however, explain the general mechanics of the vulnerabilities mentioned or discuss defensive measures and secure coding practices to prevent them.
To secure WordPress plugins against the types of issues described in CVE-2026-6455, developers should adhere to the following security principles:
- Nonce Verification: Always use WordPress nonces (
wp_create_nonceandwp_verify_nonceorcheck_admin_referer) for every state-changing request (POST, GET, or AJAX). Verification must be mandatory and should not be conditional on the presence of the nonce field itself. - SQL Preparation: Use
$wpdb->prepare()for all database queries involving user input. Never concatenate variables directly into SQL strings. For numeric values, ensure strict type casting (e.g.,(int)) or use the%dplaceholder. - Safe Deserialization: Avoid using
unserialize()on data that could be influenced by a user. Use safer alternatives likejson_decode()andjson_encode()for storing structured data. - File System Security: When handling file paths provided by users or retrieved from a database, validate the paths to prevent directory traversal. Use
basename()to strip path information and verify that the resulting file exists within the intended directory. - Principle of Least Privilege: Ensure that administrative functions check for the appropriate capabilities using
current_user_can()before executing any sensitive logic.
For further learning on securing WordPress plugins, you may find the following resources helpful:
- The WordPress Plugin Handbook section on Security.
- OWASP guidance on Cross-Site Request Forgery (CSRF) Prevention.
- OWASP guidance on SQL Injection Prevention.
Summary
The WP Contact Form 7 DB Handler plugin is vulnerable to a multi-stage attack where a Cross-Site Request Forgery (CSRF) vulnerability allows an attacker to trigger an unparameterized SQL Injection. By exploiting this SQL Injection through a UNION-based payload, an attacker can control the input to a PHP `unserialize()` call, ultimately leading to arbitrary file deletion on the server via path traversal in the file cleanup logic.
Vulnerable Code
// include/form-inner-page-class.php (v3.0) public function process_bulk_action() { global $wpdb; $table_name = $wpdb->prefix . 'posts'; $action = $this->current_action(); if (isset($_POST['_wpnonce']) && ! empty($_POST['_wpnonce'])) { $nonce = filter_input(INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING); $nonce_action = 'bulk-' . $this->_args['plural']; if (!wp_verify_nonce($nonce, $nonce_action)) { wp_die('Not valid..!!'); } } if ('delete' === $action) { if (isset($_POST['contact_form'])) { $postIds = esc_sql(wp_unslash($_POST['contact_form'])); $delete_count = 0; foreach ($postIds as $ID): $results = $wpdb->get_results("SELECT * FROM $table_name WHERE ID = $ID AND post_type = 'ys_cfdbh' LIMIT 1", OBJECT); $result_value = $results[0]->post_content; $result_values = unserialize($result_value); $upload_dir = wp_upload_dir(); $ID = $results[0]->ID; $ys_cfdbh_dirname = $upload_dir['basedir'] . '/ys_cfdbh_uploads'; foreach ($result_values as $key => $result) { if (strpos($key, 'ys_cfdbh_file') !== false) { $file_path = $ys_cfdbh_dirname . '/' . $result; if (file_exists($file_path)) { wp_delete_file($file_path); } } } $wpdb->delete( $table_name, array('ID' => $ID), array('%d') ); $delete_count++; endforeach; } // ...
Security Fix
Exploit Outline
The exploit targets the `process_bulk_action()` function via a CSRF vector against an administrative user. 1. **CSRF Bypass**: The plugin only verifies the nonce if the `_wpnonce` field is present in the POST body. By omitting the `_wpnonce` field entirely, the check is bypassed. 2. **SQL Injection**: The `contact_form` parameter is an array of IDs used in a raw SQL query (`WHERE ID = $ID`). An attacker provides a payload like `-1 UNION SELECT ...` for one of the array elements. 3. **PHP Object Injection**: The UNION SELECT is crafted to return a specific serialized string in the `post_content` column. Because the plugin calls `unserialize()` on this query result, the attacker controls the structure of the resulting PHP array. 4. **Arbitrary File Deletion**: The attacker includes a key in the serialized array containing the string 'ys_cfdbh_file' (e.g., `ys_cfdbh_file_poc`). The value associated with this key is a relative path (e.g., `../../wp-config.php`). The plugin appends this value to the uploads directory path and passes it to `wp_delete_file()`, deleting the specified file.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.