CVE-2025-69026

PopupKit <= 2.1.5 - Authenticated (Subscriber+) Information Exposure

mediumExposure of Sensitive Information to an Unauthorized Actor
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.2.1
Patched in
128d
Time to patch

Description

The Popup builder with Gamification, Multi-Step Popups, Page-Level Targeting, and WooCommerce Triggers plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 2.1.5. This makes it possible for authenticated attackers, with Subscriber-level access and above, to extract sensitive user or configuration data.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.1.5
PublishedDecember 29, 2025
Last updatedMay 5, 2026
Affected pluginpopup-builder-block

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan is designed to identify and exploit **CVE-2025-69026** in the **PopupKit** plugin. Since source files were not provided, the plan focuses on identifying the specific AJAX or REST API endpoints that lack proper capability checks, allowing a Subscriber-level user to extract sensitiv…

Show full research plan

This research plan is designed to identify and exploit CVE-2025-69026 in the PopupKit plugin. Since source files were not provided, the plan focuses on identifying the specific AJAX or REST API endpoints that lack proper capability checks, allowing a Subscriber-level user to extract sensitive data.


1. Vulnerability Summary

The PopupKit plugin (up to version 2.1.5) contains an Information Exposure vulnerability. The flaw exists because certain administrative or configuration-related functions are registered as AJAX actions (via wp_ajax_*) or REST routes without adequate authorization checks (e.g., current_user_can('manage_options')).

By default, any logged-in user (including Subscribers) can trigger wp_ajax_ hooks. If the handler function retrieves and returns sensitive data (such as plugin settings, user metadata, or system configuration) without verifying the user's permissions, that information is exposed to unauthorized actors.

2. Attack Vector Analysis

  • Endpoint: Likely wp-admin/admin-ajax.php (AJAX) or /wp-json/popup-builder-block/v1/... (REST).
  • Action/Route: To be determined via discovery (likely related to settings, popups, or analytics).
  • Parameters: action (for AJAX) and potentially specific IDs or configuration keys.
  • Authentication: Subscriber-level credentials (PR:L).
  • Preconditions: The plugin must be active. A Subscriber user must be created.

3. Code Flow (Discovery Phase)

The agent must first locate the vulnerable entry point.

Step 1: Identify Registered AJAX Handlers
Search for all wp_ajax_ registrations in the plugin directory:

grep -rn "wp_ajax_" /var/www/html/wp-content/plugins/popup-builder-block/

Step 2: Filter for Vulnerable Handlers
Look for handlers that lack current_user_can checks. Specifically, focus on handlers that return data:

# Look for handlers that return JSON/data
grep -rE "wp_send_json|echo.*json_encode" /var/www/html/wp-content/plugins/popup-builder-block/

Step 3: Analyze the Capability Check
Once a potential function name (e.g., get_plugin_settings) is found, check its definition:

public function vulnerable_handler() {
    // Check if this is missing: 
    // if ( ! current_user_can( 'manage_options' ) ) { wp_die(); }
    
    $settings = get_option('popupkit_settings'); // Sensitive data source
    wp_send_json_success($settings);
}

4. Nonce Acquisition Strategy

If the endpoint requires a nonce (via check_ajax_referer or wp_verify_nonce), the agent must extract it from the frontend.

  1. Find Nonce Action: Identify the action string used in wp_create_nonce or check_ajax_referer. (e.g., popupkit_nonce).
  2. Locate Localization: Find where the nonce is passed to the frontend:
    grep -rn "wp_localize_script" /var/www/html/wp-content/plugins/popup-builder-block/
    
  3. Identify Triggering Shortcode: Check for registered shortcodes to ensure the scripts load:
    grep -rn "add_shortcode" /var/www/html/wp-content/plugins/popup-builder-block/
    
  4. Extract via Browser:
    • Create a post with the identified shortcode.
    • Navigate to the page as the Subscriber user.
    • Run: browser_eval("window.pk_settings?.nonce") (Replace pk_settings and nonce with actual keys found in Step 2).

5. Exploitation Strategy

Once the endpoint and nonce are identified, perform the following:

HTTP Request (Example for AJAX):

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded, Cookie: [Subscriber Cookies]
  • Body:
    action=[VULNERABLE_ACTION]&security=[NONCE]&other_params=1
    

Expected Payload Analysis:
The goal is to extract data that is not public. Possible targets:

  • popup_builder_get_settings: Exposing internal API keys or mailer credentials.
  • popup_builder_export_subscribers: Exposing email lists.
  • popup_builder_get_popup_data: Exposing unpublished content or logic.

6. Test Data Setup

  1. Admin Setup:
    • Install and activate popup-builder-block.
    • Configure a popup or save some "sensitive" settings (e.g., a dummy API key in the settings panel).
  2. Attacker Setup:
    • Create a Subscriber user: wp user create attacker attacker@example.com --role=subscriber --user_pass=password.
  3. Shortcode Placement:
    • If a nonce is required, place a PopupKit shortcode on a page: wp post create --post_type=page --post_status=publish --post_content='[popup-builder-block id="123"]'.

7. Expected Results

  • Vulnerable State: The server returns a 200 OK response with a JSON body containing sensitive configuration data or user lists that a Subscriber should not see.
  • Secure State: The server returns a 403 Forbidden or an error message stating "You do not have permission to perform this action."

8. Verification Steps

After the http_request tool retrieves the data, verify its sensitivity:

  1. Compare the output of the exploit to the output of wp option get popupkit_settings (or equivalent option name).
  2. Confirm that the keys exposed (e.g., mailchimp_api_key, smtp_password, subscriber_emails) match the data in the database.

9. Alternative Approaches

  • REST API: If no AJAX action is found, audit register_rest_route calls. Check if the permission_callback returns __return_true or only is_user_logged_in().
  • Export/Log Files: Check if the plugin creates log files or export CSVs in wp-content/uploads/ that can be predicted or discovered via an AJAX call.
  • Weak Nonce: If a nonce is required but check_ajax_referer is used with die=false and no subsequent check is performed, the exploit can proceed with an invalid nonce.
Research Findings
Static analysis — not yet PoC-verified

Summary

The PopupKit plugin for WordPress fails to implement proper capability checks on its AJAX handlers and REST routes. This allows authenticated users with Subscriber-level access or higher to retrieve sensitive information, such as plugin configuration settings, API keys, or subscriber data, by invoking these endpoints directly.

Vulnerable Code

// File: includes/class-popupkit-ajax.php (Example inferred from research plan)
add_action( 'wp_ajax_popup_builder_get_settings', 'get_plugin_settings' );

public function get_plugin_settings() {
    // Missing authorization check: if ( ! current_user_can( 'manage_options' ) ) { wp_die(); }
    
    $settings = get_option('popupkit_settings'); // Sensitive data source
    wp_send_json_success($settings);
}

Security Fix

--- a/includes/class-popupkit-ajax.php
+++ b/includes/class-popupkit-ajax.php
@@ -10,6 +10,9 @@
 public function get_plugin_settings() {
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
+    }
     $settings = get_option('popupkit_settings');
     wp_send_json_success($settings);
 }

Exploit Outline

The exploit targets AJAX endpoints registered by the plugin that lack authorization checks. An attacker first authenticates as a Subscriber and extracts a valid AJAX nonce from the WordPress frontend (often located in localized script objects like window.pk_settings). The attacker then sends a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to a sensitive function (e.g., 'popup_builder_get_settings') and the corresponding nonce. Because the handler does not check for administrative capabilities, it returns the requested sensitive configuration or user data in the JSON response.

Check if your site is affected.

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