Product File Upload for WooCommerce <= 2.2.4 - Unauthenticated Arbitrary File Deletion
Description
The Product File Upload for WooCommerce plugin for WordPress is vulnerable to arbitrary file deletion due to insufficient file path validation in all versions up to, and including, 2.2.4. 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).
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:HTechnical Details
<=2.2.4What Changed in the Fix
Changes introduced in v2.2.5
Source Code
WordPress.org SVN# Research Plan: CVE-2026-25328 - Unauthenticated Arbitrary File Deletion ## 1. Vulnerability Summary The **Product File Upload for WooCommerce** plugin (versions <= 2.2.4) contains a path traversal vulnerability in its file removal functionality. The plugin exposes an unauthenticated AJAX handler …
Show full research plan
Research Plan: CVE-2026-25328 - Unauthenticated Arbitrary File Deletion
1. Vulnerability Summary
The Product File Upload for WooCommerce plugin (versions <= 2.2.4) contains a path traversal vulnerability in its file removal functionality. The plugin exposes an unauthenticated AJAX handler that accepts a file path (or name) and deletes the corresponding file using PHP's unlink() function without proper sanitization or validation that the path resides within the intended upload directory. This allows an unauthenticated attacker to delete critical system files, such as wp-config.php.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Unauthenticated Action:
superaddons_products_uploads_remove(as registered infrontend/index.php) - HTTP Method:
POST - Vulnerable Parameter:
file(inferred, based on typical removal handler patterns) - Required Nonce: Yes, the plugin requires a nonce created with the action string
'checkout_file_upload'. - Preconditions: The plugin must be active. The removal functionality is available to anyone who can access a product page to retrieve the nonce.
3. Code Flow
- Entry Point: An unauthenticated user sends a POST request to
admin-ajax.phpwith the actionsuperaddons_products_uploads_remove. - Hook Registration: In
frontend/index.php, the classSuperaddons_Products_Uploads_Frontendregisters the AJAX handler:add_action( 'wp_ajax_nopriv_superaddons_products_uploads_remove', array($this,'superaddons_products_uploads_remove') ); - Vulnerable Function: The
superaddons_products_uploads_removefunction is called. - Insecure Sink (Inferred): The function likely retrieves a path from
$_POST['file'], prepends the WordPress upload directory path, and passes the resulting string directly tounlink(). - Traversal: By providing a payload like
../../wp-config.php, the attacker escapes the intended directory and deletes the site configuration file.
4. Nonce Acquisition Strategy
The plugin enqueues a script and localizes a nonce for unauthenticated users on WooCommerce product pages.
- Identify Trigger: The nonce is enqueued via the
woocommerce_before_add_to_cart_buttonhook infrontend/index.php. This means the script (and the nonce) will be present on any single product page. - Create Content: To ensure a reliable target, create a standard WooCommerce product.
- Navigate: Use the browser to visit the product's URL.
- Extract: Execute JavaScript in the browser context to read the localized object:
- JS Variable:
superaddons_products_uploads - Nonce Key:
nonce(as seen inadd_lib()verbatim:'nonce' => wp_create_nonce('checkout_file_upload')) - Command:
browser_eval("window.superaddons_products_uploads?.nonce")
- JS Variable:
5. Exploitation Strategy
- Setup Canary: Create a file named
canary.txtin the WordPress root directory to safely test deletion. - Retrieve Nonce: Visit a product page and extract the nonce using the strategy above.
- Construct Payload:
- The removal handler likely constructs the path as
wp_upload_dir()['basedir'] . '/' . $file. - Since
basediris usuallywp-content/uploads, the traversal to reach the root is../../.
- The removal handler likely constructs the path as
- Execute Deletion: Send a POST request using
http_request.- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=superaddons_products_uploads_remove&nonce=[NONCE]&file=../../canary.txt
- URL:
- Verify: Check if
canary.txtstill exists on the filesystem.
6. Test Data Setup
- Active Plugin: Ensure
products-file-upload-for-woocommerceis installed and activated. - Woocommerce Dependency: Ensure WooCommerce is installed and basic setup is completed.
- Target Product:
wp post create --post_type=product --post_title="Exploit Target" --post_status=publish - Canary File:
echo "vulnerable" > /var/www/html/canary.txt
7. Expected Results
- The AJAX request should return a successful response (likely JSON or a '1').
- The file
/var/www/html/canary.txtshould be deleted from the server. - If targeting
wp-config.php, the site should immediately enter the WordPress installation screen upon the next refresh.
8. Verification Steps
- CLI Check: Use
lsvia the agent's shell or a similar check to confirm the canary is gone.ls /var/www/html/canary.txt - Response Check: Confirm the AJAX endpoint didn't return a 403 Forbidden (which would indicate a nonce failure).
9. Alternative Approaches
- Parameter Guessing: If
fileis not the correct parameter, tryfile_name,path, orremove_file. - Path Depth: If
../../fails, try deeper traversals (e.g.,../../../canary.txt) in case the plugin stores files in a nested subdirectory likewp-content/uploads/product-files/. - Targeting WP-Config: As a final PoC step, attempt to delete
wp-config.phpand verify the site goes towp-admin/setup-config.php.
Summary
The Product File Upload for WooCommerce plugin is vulnerable to unauthenticated arbitrary file deletion due to a lack of sanitization and path validation in its file removal functionality. An attacker can exploit this by providing a path traversal string (e.g., ../../wp-config.php) via an AJAX request, leading to the deletion of critical system files and potentially full site takeover.
Vulnerable Code
// frontend/index.php lines 11-12 (v2.2.3) add_action( 'wp_ajax_woo_superaddons_products_uploads_remove', array($this,'superaddons_products_uploads_remove') ); add_action( 'wp_ajax_nopriv_woo_superaddons_products_uploads_remove', array($this,'superaddons_products_uploads_remove') ); --- // assets/js/drap_drop_file_upload.js lines 201-207 (v2.2.3) $("body").on("click",".products-uploads_file_upload_remove",function(e){ e.preventDefault(); var cr_name = $(this).data("name") ; var data = { 'action': 'superaddons_products_uploads_remove', 'name' : cr_name, 'nonce': superaddons_products_uploads.nonce };
Security Fix
@@ -200,22 +201,24 @@ $("body").on("click",".products-uploads_file_upload_remove",function(e){ e.preventDefault(); var cr_name = $(this).data("name") ; + console.log(cr_name); var data = { 'action': 'superaddons_products_uploads_remove', 'name' : cr_name, 'nonce': superaddons_products_uploads.nonce }; var name = $('#woo_products_upload_files').val().split("|"); + console.log(name); for (var i=name.length-1; i>=0; i--) { if (name[i] === cr_name) { name.splice(i, 1); } } - $('#woo_sing_upload_files').val(name.join("|")); + $('#woo_products_upload_files').val(name.join("|")); $(this).closest('.products-uploads-drop-statusbar').remove(); jQuery.post(superaddons_products_uploads.ajax_url, data, function(response) { }); return false; }) }) - })(jQuery); + })(jQuery);
Exploit Outline
The exploit targets the unauthenticated AJAX action 'superaddons_products_uploads_remove' (or 'woo_superaddons_products_uploads_remove' depending on version). An attacker first retrieves a valid nonce by visiting any WooCommerce product page where the plugin is active, extracting it from the localized 'superaddons_products_uploads' JavaScript object. The attacker then sends a POST request to 'wp-admin/admin-ajax.php' with the 'action' parameter set to the removal hook, the 'nonce' parameter, and a 'name' parameter containing a path traversal payload such as '../../wp-config.php'. Because the server-side implementation fails to validate that the provided file name is restricted to the intended upload directory, it passes the manipulated path directly to a file system removal function like unlink(), deleting the target file.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.