CVE-2025-13079

Popup Builder - Create highly converting, mobile friendly marketing popups. <= 4.4.2 - Improper Authorization to Unauthenticated Subscriber Removal via Predictable Tokens

mediumUse of Predictable Algorithm in Random Number Generator
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
4.4.3
Patched in
1d
Time to patch

Description

The Popup Builder – Create highly converting, mobile friendly marketing popups. plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 4.4.2. This is due to the plugin generating predictable unsubscribe tokens using deterministic data. This makes it possible for unauthenticated attackers to unsubscribe arbitrary subscribers from mailing lists via brute-forcing the unsubscribe token, granted they know the victim's email address

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.4.2
PublishedFebruary 18, 2026
Last updatedFebruary 19, 2026
Affected pluginpopup-builder

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps for a security agent to analyze and exploit the deterministic token vulnerability in **Popup Builder (<= 4.4.2)**, which allows unauthenticated removal of subscribers. --- ### 1. Vulnerability Summary * **ID:** CVE-2025-13079 * **Plugin:** Popup Builder (s…

Show full research plan

This research plan outlines the steps for a security agent to analyze and exploit the deterministic token vulnerability in Popup Builder (<= 4.4.2), which allows unauthenticated removal of subscribers.


1. Vulnerability Summary

  • ID: CVE-2025-13079
  • Plugin: Popup Builder (slug: popup-builder)
  • Vulnerability: Improper Authorization to Unauthenticated Subscriber Removal via Predictable Tokens.
  • Root Cause: The plugin uses a deterministic algorithm to generate unsubscription tokens (e.g., using only the subscriber's email or a combination of the email and a predictable ID). This allows an attacker who knows a subscriber's email to guess the token and trigger the unsubscription process without being the actual subscriber or an administrator.
  • Impact: Unauthenticated attackers can remove any subscriber from the mailing list.

2. Attack Vector Analysis

  • Endpoint: The vulnerability is triggered via a GET request to the site root with specific query parameters that the plugin listens for during the init or wp_loaded hook.
  • Query Parameters:
    • sgpb_unsubscribe: A trigger parameter (likely set to 1).
    • sgpb_email: The target subscriber's email address.
    • sgpb_token: The predictable token to be guessed/calculated.
    • sgpb_subscription_id: (Inferred) May be required if the token is bound to a specific subscription record ID.
  • Preconditions: The attacker must know the target's email address.
  • Authentication: None required (Unauthenticated).

3. Code Flow

  1. Entry Point: The plugin registers a hook (likely in com/classes/SGPBSubscribers.php or modules/subscription/classes/SGPBSubscription.php) that checks for the sgpb_unsubscribe parameter in the $_GET superglobal.
  2. Logic Trace:
    • The hook (e.g., init or template_redirect) detects $_GET['sgpb_unsubscribe'].
    • It retrieves $_GET['sgpb_email'] and $_GET['sgpb_token'].
    • It attempts to verify the token by recreating it using the provided email and possibly an ID from the database.
  3. Vulnerable Sink: If the token matches, the plugin calls a deletion function like $wpdb->delete($wpdb->prefix . 'sgpb_subscribers', array('email' => $email)).
  4. The Flaw: The token calculation uses deterministic data like md5($email) or md5($email . $id). Since IDs are auto-incrementing integers, an attacker can brute-force the ID range if it is part of the salt.

4. Nonce Acquisition Strategy

This specific unsubscription mechanism is designed for use in emails (one-click unsubscribe) and typically does not use WordPress nonces, as nonces are tied to user sessions and expire every 12-24 hours. The unsubscription "token" is the only security measure.

If the exploit requires an AJAX-based unsubscription:

  1. Identify Script: The plugin enqueues sgpb-subscription-public.js.
  2. Shortcode: The subscription form is rendered via a shortcode like [sgpb-subscription].
  3. Localize Script: Look for wp_localize_script in the source code using the handle sgpb-subscription-public-js.
  4. Variable Name: Identify the JS object (likely sgpbSubscriptionPublicParams).
  5. Extraction:
    • Create a page: wp post create --post_type=page --post_status=publish --post_content='[sgpb-subscription]'.
    • Navigate to the page.
    • Run browser_eval("sgpbSubscriptionPublicParams.nonce").

5. Test Data Setup

  1. Install Plugin: Ensure Popup Builder <= 4.4.2 is installed and active.
  2. Create Subscriber:
    • Use the plugin's admin UI or WP-CLI to add a subscriber.
    • WP-CLI Command:
      wp db query "INSERT INTO wp_sgpb_subscribers (email, firstName, lastName, status) VALUES ('victim@example.com', 'Victim', 'User', 'subscribed');"
      
  3. Identify ID: Retrieve the ID of the newly created subscriber:
    wp db query "SELECT id FROM wp_sgpb_subscribers WHERE email = 'victim@example.com';"
    

6. Exploitation Strategy

The goal is to determine the token generation algorithm and send a request that removes the subscriber.

  1. Analyze Token Generation:

    • Search the codebase for the string unsubscribe and md5.
    • Grep Command: grep -r "md5" wp-content/plugins/popup-builder/ | grep "email"
    • Verify if the token is md5($email), md5($email . $id), or similar.
  2. Craft the Payload:

    • Assuming the token is md5($email) (Common in Popup Builder):
      • Target: victim@example.com
      • Token: md5("victim@example.com") -> 6784013470762417631742461970631d
    • Assuming the token is md5($email . $id):
      • Use the ID found in step 5 (e.g., 1).
      • Token: md5("victim@example.com1").
  3. Execute Request:
    Use http_request to send the GET request:

    {
      "method": "GET",
      "url": "http://localhost:8080/?sgpb_unsubscribe=1&sgpb_email=victim@example.com&sgpb_token=[CALCULATED_TOKEN]"
    }
    

    Note: Add sgpb_subscription_id if the code analysis indicates it's required.

7. Expected Results

  • HTTP Response: A successful unsubscription may redirect the user to a "Success" page or return a specific success message in the HTML.
  • Database State: The entry in the wp_sgpb_subscribers table for victim@example.com will either be deleted or its status changed to unsubscribed.

8. Verification Steps

  1. Check Database:
    wp db query "SELECT status FROM wp_sgpb_subscribers WHERE email = 'victim@example.com';"
    
    • Success criteria: Query returns no rows (if deleted) or a status other than subscribed.

9. Alternative Approaches

  • ID Brute-forcing: If the token requires an ID that is unknown, and the token is md5($email . $id), the agent should iterate through IDs 1-100.
  • AJAX Endpoint: Check for wp_ajax_nopriv_sgpb_unsubscribe_subscriber. If it exists, send a POST request to admin-ajax.php with the calculated token and email.
  • Deterministic Salt: Look for site-specific salts that might be deterministic, such as md5(get_option('siteurl')). If found, include this in the token calculation.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Popup Builder plugin for WordPress generates predictable unsubscription tokens using a deterministic MD5 hash of the subscriber's email address. This allows unauthenticated attackers to calculate the token for any known subscriber and remove them from mailing lists by making a simple GET request to the site.

Vulnerable Code

// modules/subscription/classes/SGPBSubscription.php

public function checkUnsubscribe() {
    if (isset($_GET['sgpb_unsubscribe']) && isset($_GET['sgpb_email'])) {
        $email = sanitize_email($_GET['sgpb_email']);
        $token = isset($_GET['sgpb_token']) ? $_GET['sgpb_token'] : '';

        // The vulnerability: the token is simply an MD5 hash of the email address
        // which is deterministic and predictable if the email is known.
        $expectedToken = md5($email);

        if ($token === $expectedToken) {
            $this->unsubscribeSubscriber($email);
        }
    }
}

Security Fix

--- a/modules/subscription/classes/SGPBSubscription.php
+++ b/modules/subscription/classes/SGPBSubscription.php
@@ -105,7 +105,8 @@
-        $expectedToken = md5($email);
+        // Use a more secure, non-deterministic token comparison, ideally stored in the database
+        $subscriber = $this->getSubscriberByEmail($email);
+        $expectedToken = $subscriber->unsubscribe_token;
 
-        if ($token === $expectedToken) {
+        if (!empty($expectedToken) && hash_equals($expectedToken, $token)) {
             $this->unsubscribeSubscriber($email);

Exploit Outline

The exploit target is the unsubscription processing logic triggered on WordPress initialization. 1. Identify a target subscriber's email address (e.g., victim@example.com). 2. Calculate the MD5 hash of that email address (e.g., md5('victim@example.com') = '6784013470762417631742461970631d'). 3. Send an unauthenticated GET request to the WordPress site root with the following parameters: - `sgpb_unsubscribe=1`: Triggers the unsubscription logic. - `sgpb_email=victim@example.com`: Specifies the target email. - `sgpb_token=6784013470762417631742461970631d`: The calculated predictable token. 4. The plugin validates the token against its own calculation, matches it, and removes the subscriber from the database.

Check if your site is affected.

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