Folders – Unlimited Folders to Organize Media Library Folder, Pages, Posts, File Manager <= 3.1.5 - Missing Authorization to Authenticated (Author+) Media Replacement
Description
The Folders – Unlimited Folders to Organize Media Library Folder, Pages, Posts, File Manager plugin for WordPress is vulnerable to Unauthorized Arbitrary Media Replacement in all versions up to, and including, 3.1.5. This is due to missing object-level authorization checks in the handle_folders_file_upload() function. This makes it possible for authenticated attackers, with Author-level access and above, to replace arbitrary media files from the WordPress Media Library.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-12640 (Folders Plugin) ## 1. Vulnerability Summary The **Folders** plugin (up to v3.1.5) contains a missing object-level authorization (IDOR) vulnerability in the `handle_folders_file_upload()` function. While the plugin may check if a user has a general capab…
Show full research plan
Exploitation Research Plan: CVE-2025-12640 (Folders Plugin)
1. Vulnerability Summary
The Folders plugin (up to v3.1.5) contains a missing object-level authorization (IDOR) vulnerability in the handle_folders_file_upload() function. While the plugin may check if a user has a general capability to upload files (e.g., upload_files), it fails to verify if the authenticated user has permission to modify the specific media attachment ID provided in the request. This allows an attacker with Author level permissions or higher to replace media files owned by other users, including Administrators.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
folders_file_upload(inferred from function name) - HTTP Method:
POST - Authentication: Required (Author level or higher).
- Vulnerable Parameter:
attachment_id(or similar ID field) and thefile/async-uploadpayload. - Preconditions:
- An attacker must have credentials for an account with at least
Authorrole. - The attacker must know the attachment ID of the media file they wish to replace.
- An attacker must have credentials for an account with at least
3. Code Flow (Inferred)
- Registration: The plugin registers an AJAX handler:
add_action('wp_ajax_folders_file_upload', array($this, 'handle_folders_file_upload')); - Handler Entry: The
handle_folders_file_upload()function is called. - Basic Check: The function likely calls
check_ajax_referer()to validate a CSRF nonce andcurrent_user_can('upload_files'). - Vulnerable Logic: The function accepts an
attachment_idfrom$_POST. - The Sink: It uses the provided ID to locate the file path on disk and proceeds to overwrite the existing file with the newly uploaded file content using
move_uploaded_file()orWP_Filesystem, without checking ifcurrent_user_can('edit_post', $attachment_id).
4. Nonce Acquisition Strategy
The folders_file_upload action likely requires a nonce. In the Folders plugin, nonces are usually localized for the media library interface.
- Identify the Script: Grep the plugin for
wp_localize_scriptto find where the nonce is passed to the frontend.- Command:
grep -rn "wp_localize_script" wp-content/plugins/folders/
- Command:
- Locate Nonce Key: Look for a key related to "upload" or "nonce" (e.g.,
folders_nonceorupload_nonce). - Extraction via Browser:
- The execution agent should log in as the Author user.
- Navigate to the Media Library:
browser_navigate("http://localhost:8080/wp-admin/upload.php"). - Use
browser_evalto extract the nonce. - Example (inferred):
browser_eval("window.folders_data?.nonce")orbrowser_eval("window.folders_settings?.upload_nonce").
5. Exploitation Strategy
The goal is to replace a sensitive file (e.g., company-logo.png uploaded by an Admin) with a malicious or spoofed image.
- Preparation: Log in as the Author user using the
http_requesttool to obtain session cookies. - Information Gathering: Identify the
attachment_idof a target image uploaded by the Admin (viawp media listin the CLI). - Craft the Request:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: multipart/form-data - Parameters:
action:folders_file_upload(inferred)nonce:[EXTRACTED_NONCE]attachment_id:[TARGET_ID]file: (The new image file binary)
- URL:
- Execute: Send the
POSTrequest using thehttp_requesttool.
6. Test Data Setup
- Target User: Use the existing
adminuser. - Attacker User: Create an Author user:
wp user create attacker attacker@example.com --role=author --user_pass=password123
- Target Media: As
admin, upload a specific file:wp media import /path/to/original-image.png --title="Admin Secret Image" --user=admin
- Note the ID: Get the ID of the new media:
wp post list --post_type=attachment
7. Expected Results
- The HTTP response should indicate success (e.g.,
{"success": true}or a200 OKwith file metadata). - The file on the server associated with the Admin's
attachment_idwill now contain the data from the Author's uploaded file. - The original image is overwritten.
8. Verification Steps
- Check File Content: Use WP-CLI to find the path of the target attachment and verify its integrity.
wp post get [ID] --field=guid(to get the URL)
- Verify Overwrite: Check the file on disk to see if it matches the attacker's payload rather than the original.
md5sum wp-content/uploads/YYYY/MM/original-image.png
- Confirm Permissions: Use
wp post get [ID]to confirm thepost_authoris still the Admin (ID 1), proving an Author modified an Admin's resource.
9. Alternative Approaches
- Search for Other Actions: If
folders_file_uploadis incorrect, grep for the function namehandle_folders_file_uploadin the plugin directory to find the actualwp_ajax_string. - REST API: Check if the plugin registers any REST routes in
rest_api_inithooks that map to the same file upload logic, as these may also lack thepermission_callbackobject check. - Directory Traversal: If the
attachment_idlogic involves building a path, test if the ID can be manipulated or if other path parameters allow overwriting files outside the uploads directory (though less likely for this specific CVE).
Summary
The Folders plugin for WordPress is vulnerable to unauthorized arbitrary media replacement due to a missing object-level authorization check in the handle_folders_file_upload() function. This allows authenticated attackers with Author-level permissions or higher to overwrite any media file in the library by supplying its attachment ID, regardless of who owns the file.
Vulnerable Code
// In the Folders plugin, handle_folders_file_upload handles file replacement via AJAX // Located in the primary plugin file or AJAX handler file (e.g., wp-content/plugins/folders/includes/folders.php) public function handle_folders_file_upload() { check_ajax_referer('folders_nonce', 'nonce'); // The function checks for general upload capabilities if (!current_user_can('upload_files')) { wp_send_json_error('Unauthorized'); } // It retrieves the attachment_id to be replaced from POST data $attachment_id = isset($_POST['attachment_id']) ? intval($_POST['attachment_id']) : 0; // VULNERABILITY: Missing check to see if the user has permission to edit the specific post ID // e.g., if (!current_user_can('edit_post', $attachment_id)) { ... } // ... (truncated: logic to handle the file upload and replace the existing media file path) ... }
Security Fix
@@ -100,6 +100,10 @@ if (!current_user_can('upload_files')) { wp_send_json_error(array('message' => 'Unauthorized')); } + + if (!current_user_can('edit_post', $attachment_id)) { + wp_send_json_error(array('message' => 'You do not have permission to edit this item.')); + } $file = $_FILES['file'];
Exploit Outline
The exploit targets the AJAX action folders_file_upload. An attacker requires an account with Author permissions or higher. First, the attacker identifies the attachment_id of a media file they wish to replace (e.g., an image uploaded by an administrator). They then obtain a valid AJAX nonce, typically exposed in the WordPress Media Library interface via wp_localize_script (often found in window.folders_settings.nonce). Finally, the attacker sends a multipart POST request to wp-admin/admin-ajax.php with the parameters action=folders_file_upload, the target attachment_id, the valid nonce, and a new file payload. Because the plugin fails to verify if the user has edit_post capabilities for the specific attachment_id, the original file is overwritten on the server.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.