Simple File List <= 6.3.7 - Unauthenticated Arbitrary File Deletion via Path Traversal in 'eeSubFolder' Parameter
Description
The Simple File List plugin for WordPress is vulnerable to arbitrary file deletion due to insufficient file path validation in the eeSFL_DeleteFile function in all versions up to, and including, 6.3.7. 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 simplefilelist_edit_job AJAX action is registered via wp_ajax_nopriv_, making it accessible without authentication, and the is_admin() guard that would otherwise restrict access is bypassed because is_admin() always returns true for requests to the admin-ajax.php endpoint.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=6.3.7What Changed in the Fix
Changes introduced in v6.3.8
Source Code
WordPress.org SVNI cannot fulfill your request. I am prohibited from generating actionable exploitation research plans, functional attack payloads, or step-by-step guides for exploiting software vulnerabilities. You may search for information regarding WordPress security best practices and methods for preventing pat…
Show full research plan
I cannot fulfill your request. I am prohibited from generating actionable exploitation research plans, functional attack payloads, or step-by-step guides for exploiting software vulnerabilities. You may search for information regarding WordPress security best practices and methods for preventing path traversal vulnerabilities in PHP online to learn more about defensive programming and securing plugin file operations.
Summary
The Simple File List plugin for WordPress is vulnerable to unauthenticated arbitrary file deletion due to a combination of broken authorization checks and a path traversal flaw in the 'eeSubFolder' parameter. An attacker can exploit this to delete critical system files, such as wp-config.php, potentially leading to a full site takeover or remote code execution.
Vulnerable Code
// includes/ee-functions.php line 1262 // Check if we should be doing this if(!is_admin() AND $eeSFL->eeListSettings['AllowFrontManage'] != 'YES') { eeSFL_Debug_Log("ERROR: Front manage not allowed", 'Admin', $eeSFL->eeListID); return; } // ... // includes/ee-functions.php line 1288 $eeSubFolder = FALSE; if( isset($_POST['eeSubFolder']) && !empty($_POST['eeSubFolder']) ) { $eeSubFolderRaw = sanitize_text_field(wp_unslash($_POST['eeSubFolder'])); $eeSubFolder = urldecode($eeSubFolderRaw); } --- // includes/ee-functions.php line 894 // Path construction $eeFilePath = eeSFL_WP_ROOT . $eeSFL->eeListSettings['FileListDir'] . $eeSubFolderPath . $eeFileName; eeSFL_Debug_Log("DELETE: Full path: '$eeFilePath'", 'FileOps', $eeSFL->eeListID); $eeMessages[] = $eeSFL->eeListSettings['FileListDir'] . $eeFileName; // Check if it's a file if( eeSFL_FileSystem('is_file', array('file' => $eeFilePath))['data'] ) { $eeSFL_Result = eeSFL_FileSystem('delete', array('file' => $eeFilePath));
Security Fix
@@ -882,11 +882,9 @@ global $eeSFL, $eeSFLF; eeSFL_Debug_Log("DELETE: Starting delete operation for '$eeFileName'", 'FileOps', $eeSFL->eeListID); - eeSFL_Debug_Log("DELETE: Subfolder received: " . wp_json_encode($eeSubFolder), 'FileOps', $eeSFL->eeListID); // Normalize subfolder - convert '/' or FALSE to empty string $eeSubFolderPath = ($eeSubFolder && $eeSubFolder !== '/') ? $eeSubFolder : ''; - eeSFL_Debug_Log("DELETE: Normalized subfolder: '$eeSubFolderPath'", 'FileOps', $eeSFL->eeListID); $eeMessages = array('Deleting File'); @@ -894,6 +892,15 @@ $eeFilePath = eeSFL_WP_ROOT . $eeSFL->eeListSettings['FileListDir'] . $eeSubFolderPath . $eeFileName; eeSFL_Debug_Log("DELETE: Full path: '$eeFilePath'", 'FileOps', $eeSFL->eeListID); + // Confinement check — ensure the resolved path stays within the list directory. + // Guards against path traversal in both $eeSubFolder (Pro) and $eeFileName. + $eeBaseDir = realpath(eeSFL_WP_ROOT . $eeSFL->eeListSettings['FileListDir']); + $eeRealPath = realpath($eeFilePath); + if( $eeBaseDir && $eeRealPath && strpos($eeRealPath, $eeBaseDir) !== 0 ) { + eeSFL_Debug_Log("ERROR: Path traversal attempt blocked: '$eeFilePath'", 'FileOps', $eeSFL->eeListID); + return 'ERROR: Invalid path'; + } + $eeMessages[] = $eeSFL->eeListSettings['FileListDir'] . $eeFileName; // Check if it's a file @@ -1262,7 +1269,10 @@ $eeSFL->eeSFL_GetSettings($eeSFL->eeListID); // Check if we should be doing this - if(!is_admin() AND $eeSFL->eeListSettings['AllowFrontManage'] != 'YES') { + // Note: is_admin() is NOT a user-identity check — it is TRUE for ALL admin-ajax.php requests, + // including unauthenticated nopriv ones. Use current_user_can() for authorization. + // When AllowFrontManage = YES the gate is intentionally open to all page visitors (by design). + if( !current_user_can('manage_options') AND $eeSFL->eeListSettings['AllowFrontManage'] != 'YES' ) { eeSFL_Debug_Log("ERROR: Front manage not allowed", 'Admin', $eeSFL->eeListID); return; } @@ -1285,13 +1295,12 @@ return "Missing the File Name"; } - // Are we in a Folder? + // Subfolder support is a Pro feature — the free version always operates on the root directory. + // The eeSubFolder POST parameter is intentionally ignored here to eliminate the path traversal + // attack surface entirely (CVE-2026-11911). Pro: apply path traversal sanitization wherever + // eeSubFolder is read from POST — strip ../ sequences and validate the resolved path stays + // within FileListDir using realpath() before passing to eeSFL_DeleteFile() / eeSFL_RenameFile(). $eeSubFolder = FALSE; - if( isset($_POST['eeSubFolder']) && !empty($_POST['eeSubFolder']) ) { - $eeSubFolderRaw = sanitize_text_field(wp_unslash($_POST['eeSubFolder'])); - $eeSubFolder = urldecode($eeSubFolderRaw); - } - if(!$eeSubFolder OR $eeSubFolder == '/') { $eeSubFolder = FALSE; }
Exploit Outline
To exploit this vulnerability, an attacker can make an unauthenticated POST request to the WordPress AJAX endpoint. 1. **Endpoint**: Target `wp-admin/admin-ajax.php`. 2. **Action**: Use the `simplefilelist_edit_job` action, which is registered for unauthenticated users via `wp_ajax_nopriv_`. 3. **Payload**: - Set `eeFileAction` to `delete`. - Set `eeFileName` to the target file name (e.g., `wp-config.php`). - Set `eeSubFolder` to a path traversal string (e.g., `../../../../`) to move the operation outside of the intended directory. 4. **Authentication**: No authentication is required because the plugin uses `is_admin()` for an authorization check, which incorrectly returns `true` for all AJAX requests, effectively bypassing the security guard.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.