Pix for WooCommerce <= 1.5.0 - Unauthenticated Arbitrary File Upload
Description
The Pix for WooCommerce plugin for WordPress is vulnerable to arbitrary file uploads due to missing capability check and missing file type validation in the 'lkn_pix_for_woocommerce_c6_save_settings' function in all versions up to, and including, 1.5.0. This makes it possible for unauthenticated attackers to upload arbitrary files on the affected site's server which may make remote code execution possible.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=1.5.0What Changed in the Fix
Changes introduced in v1.6.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-3891 (Pix for WooCommerce Arbitrary File Upload) ## 1. Vulnerability Summary The **Pix for WooCommerce** plugin (up to 1.5.0) is vulnerable to an **Unauthenticated Arbitrary File Upload**. The vulnerability resides in the `lkn_pix_for_woocommerce_c6_save_setti…
Show full research plan
Exploitation Research Plan: CVE-2026-3891 (Pix for WooCommerce Arbitrary File Upload)
1. Vulnerability Summary
The Pix for WooCommerce plugin (up to 1.5.0) is vulnerable to an Unauthenticated Arbitrary File Upload. The vulnerability resides in the lkn_pix_for_woocommerce_c6_save_settings function (and potentially similar functions for Cielo and Rede gateways).
The plugin provides a "Nonce Oracle" endpoint (lkn_pix_for_woocommerce_generate_nonce) that allows any user (including unauthenticated ones) to generate a valid WordPress nonce for any action. This nonce can then be used to authenticate requests to the vulnerable settings-saving AJAX actions. These actions fail to perform capability checks (current_user_can) and do not validate file types or extensions, allowing for the upload of PHP shells.
2. Attack Vector Analysis
- Endpoints:
/wp-admin/admin-ajax.php - Actions:
lkn_pix_for_woocommerce_generate_nonce(To obtain the required nonce)lkn_pix_for_woocommerce_c6_save_settings(The file upload sink)
- Parameters:
action_name: The action string for which to generate a nonce._ajax_nonce: The generated nonce.settings: JSON-encoded settings string.- File fields: The file to be uploaded (e.g.,
certificate).
- Authentication: Unauthenticated (assumed based on the CVE description and the absence of checks in the provided
generate_noncemethod). - Preconditions: WooCommerce must be active (the plugin depends on it).
3. Code Flow
- Entry Point (Oracle): An attacker sends a request to
admin-ajax.phpwithaction=lkn_pix_for_woocommerce_generate_nonce. - Nonce Generation: The method
LknPaymentPixForWoocommerceAdmin::generate_nonce(line 140 inAdmin/LknPaymentPixForWoocommerceAdmin.php) reads theaction_namefrom the request and callswp_create_nonce($action)without any permission check. It returns the nonce. - Entry Point (Upload): The attacker sends a multipart POST request to
admin-ajax.phpwithaction=lkn_pix_for_woocommerce_c6_save_settings. - Verification: The handler for this action (likely in the
LknPaymentPixForWoocommercePixC6class) verifies the nonce provided in_ajax_nonce. Because the attacker obtained a valid nonce from the Oracle, this check passes. - Sink: The handler processes
$_FILES. Based on the frontend JS (Admin/js/pixForWoocommercePaymentAdminSaveFields.jsline 62), it iterates through fields and appends them to aFormDataobject. The backend likely saves these files usingwp_handle_uploadormove_uploaded_filewithout extension filtering.
4. Nonce Acquisition Strategy
This plugin provides an explicit Nonce Oracle which makes browser-based extraction or shortcode-page creation unnecessary.
- Action to generate:
lkn_pix_for_woocommerce_c6_settings_nonce(derived fromAdmin/js/pixForWoocommercePaymentAdminSaveFields.jsline 111). - Request:
POST /wp-admin/admin-ajax.php Content-Type: application/x-www-form-urlencoded action=lkn_pix_for_woocommerce_generate_nonce&action_name=lkn_pix_for_woocommerce_c6_settings_nonce - Extraction: Parse the JSON response:
response.data.nonce.
5. Exploitation Strategy
Step 1: Obtain the Nonce
Call the Oracle to get a valid nonce for the C6 settings save action.
Step 2: Upload the PHP Shell
Send a multipart/form-data request to the C6 save settings action.
- Action:
lkn_pix_for_woocommerce_c6_save_settings - Field Name:
certificate(This is a common field for bank gateway integrations requiring certificates). - Settings JSON:
{"certificate":"shell.php"}
Step 3: Locate the Shell
The file will typically be uploaded to the WordPress uploads directory.
wp-content/uploads/yyyy/mm/shell.php- Alternatively, check if the plugin creates a specific directory like
wp-content/uploads/pix-for-woocommerce/.
6. Test Data Setup
- Ensure WooCommerce is installed and active.
- Ensure "Pix for WooCommerce" is installed and active (version <= 1.5.0).
- No specific settings are required because the AJAX handlers are exposed via
wp_ajax_nopriv_(as per the "Unauthenticated" severity).
7. Expected Results
- The Nonce Oracle returns a 10-character hexadecimal string.
- The upload request returns a success message (e.g.,
{"success":true,"data":{"message":"Settings saved successfully"}}). - A PHP file is created on the server and is executable.
8. Verification Steps
- Direct Execution: Access the uploaded file via the browser:
http://localhost:8080/wp-content/uploads/2025/05/shell.php?cmd=id - WP-CLI Check: Confirm the file exists on disk:
find /var/www/html/wp-content/uploads -name "shell.php" - Database Check: Check the WooCommerce option for the gateway to see the stored file path:
wp option get woocommerce_lkn_pix_for_woocommerce_c6_settings --format=json
9. Alternative Approaches
If the c6 endpoint is restricted or the field name is different, try the other gateways supported by the plugin using their respective suffixes and field names:
- Cielo:
- Action:
lkn_pix_for_woocommerce_cielo_pix_save_settings - Nonce Action:
lkn_pix_for_woocommerce_cielo_pix_settings_nonce
- Action:
- Rede:
- Action:
lkn_pix_for_woocommerce_rede_pix_save_settings - Nonce Action:
lkn_pix_for_woocommerce_rede_pix_settings_nonce
- Action:
If certificate is not the correct field name, fuzz the multipart field name with common candidates: cert, key, pix_cert, client_cert. The JS code implies the field name is whatever follows the woocommerce_lkn_pix_for_woocommerce_c6_ prefix in the original form.
Summary
The Pix for WooCommerce plugin (versions <= 1.5.0) is vulnerable to unauthenticated arbitrary file uploads. This is achieved by combining a 'nonce oracle' endpoint that generates valid security tokens for any user with AJAX handlers that lack capability checks and file type validation, allowing attackers to upload PHP shells and execute remote code.
Vulnerable Code
// Admin/LknPaymentPixForWoocommerceAdmin.php:140 public function generate_nonce() { if (empty($_REQUEST['action_name'])) { wp_send_json_error(['message' => 'Missing action_name parameter.'], 400); } $action = sanitize_text_field(wp_unslash($_REQUEST['action_name'])); $nonce = wp_create_nonce($action); wp_send_json_success(['nonce' => $nonce, 'action' => $action]); } --- // Includes/LknPaymentPixForWoocommerce.php:183 $this->loader->add_action('wp_ajax_lkn_pix_for_woocommerce_c6_save_settings', $this->LknPaymentPixForWoocommercePixC6Class, 'lkn_pix_for_woocommerce_c6_save_settings'); $this->loader->add_action('wp_ajax_nopriv_lkn_pix_for_woocommerce_c6_save_settings', $this->LknPaymentPixForWoocommercePixC6Class, 'lkn_pix_for_woocommerce_c6_save_settings'); $this->loader->add_action('wp_ajax_lkn_pix_for_woocommerce_generate_nonce', $plugin_admin, 'generate_nonce'); $this->loader->add_action('wp_ajax_nopriv_lkn_pix_for_woocommerce_generate_nonce', $plugin_admin, 'generate_nonce');
Security Fix
@@ -158,16 +158,4 @@ ); } } - - public function generate_nonce() - { - if (empty($_REQUEST['action_name'])) { - wp_send_json_error(['message' => 'Missing action_name parameter.'], 400); - } - - $action = sanitize_text_field(wp_unslash($_REQUEST['action_name'])); - $nonce = wp_create_nonce($action); - - wp_send_json_success(['nonce' => $nonce, 'action' => $action]); - } } @@ -178,11 +184,10 @@ $this->loader->add_action('woocommerce_update_options_payment_gateways_' . $this->LknPaymentPixForWoocommercePixC6Class->id, $this->LknPaymentPixForWoocommercePixC6Class, "process_admin_options"); $this->loader->add_action('woocommerce_order_details_after_order_table', $this->LknPaymentPixForWoocommercePixC6Class, "showPix"); $this->loader->add_action('wp_ajax_lkn_pix_for_woocommerce_c6_save_settings', $this->LknPaymentPixForWoocommercePixC6Class, 'lkn_pix_for_woocommerce_c6_save_settings'); - $this->loader->add_action('wp_ajax_nopriv_lkn_pix_for_woocommerce_c6_save_settings', $this->LknPaymentPixForWoocommercePixC6Class, 'lkn_pix_for_woocommerce_c6_save_settings'); - $this->loader->add_action('wp_ajax_lkn_pix_for_woocommerce_generate_nonce', $plugin_admin, 'generate_nonce'); - $this->loader->add_action('wp_ajax_nopriv_lkn_pix_for_woocommerce_generate_nonce', $plugin_admin, 'generate_nonce'); + // SECURITY: Removed wp_ajax_nopriv_ hooks to prevent unauthenticated access + // SECURITY: Removed insecure generate_nonce functionality - each gateway generates its own nonces $this->loader->add_action('wp_ajax_pixforwoo_test_c6_pix_charge', $this->LknPaymentPixForWoocommercePixC6Class, 'pixforwoo_test_c6_pix_charge'); - $this->loader->add_action('wp_ajax_nopriv_pixforwoo_test_c6_pix_charge', $this->LknPaymentPixForWoocommercePixC6Class, 'pixforwoo_test_c6_pix_charge'); + // SECURITY: Removed wp_ajax_nopriv_pixforwoo_test_c6_pix_charge - test integration requires authentication
Exploit Outline
The exploit methodology involves three primary steps. First, an unauthenticated attacker hits the `/wp-admin/admin-ajax.php` endpoint with the `action=lkn_pix_for_woocommerce_generate_nonce` and `action_name=lkn_pix_for_woocommerce_c6_settings_nonce` parameters to obtain a valid WordPress nonce. Second, the attacker sends a multipart POST request to the same AJAX endpoint with `action=lkn_pix_for_woocommerce_c6_save_settings`, providing the stolen nonce in the `_ajax_nonce` field. This request includes a PHP shell payload in a file field (e.g., `certificate`) and a corresponding JSON entry in the `settings` parameter. Third, because the plugin fails to check user capabilities or filter file extensions, the PHP file is saved to the WordPress uploads directory, allowing the attacker to navigate to the file and execute arbitrary commands.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.