CVE-2026-1165

Popup Box <= 6.1.1 - Cross-Site Request Forgery to Popup Status Change

mediumCross-Site Request Forgery (CSRF)
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
6.1.2
Patched in
2d
Time to patch

Description

The Popup Box plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 6.1.1. This is due to a flawed nonce implementation in the 'publish_unpublish_popupbox' function that verifies a self-created nonce rather than one submitted in the request. This makes it possible for unauthenticated attackers to change the publish status of popups via a forged request, granted they can trick a site administrator into performing an action such as clicking a link.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=6.1.1
PublishedJanuary 30, 2026
Last updatedJanuary 31, 2026
Affected pluginays-popup-box

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting a Cross-Site Request Forgery (CSRF) vulnerability in the **Popup Box** plugin for WordPress. The vulnerability allows an unauthenticated attacker to change the status (publish/unpublish) of popups by tricking an administrator into making a forged request. --…

Show full research plan

This research plan focuses on exploiting a Cross-Site Request Forgery (CSRF) vulnerability in the Popup Box plugin for WordPress. The vulnerability allows an unauthenticated attacker to change the status (publish/unpublish) of popups by tricking an administrator into making a forged request.


1. Vulnerability Summary

  • Vulnerability: Cross-Site Request Forgery (CSRF)
  • Affected Function: publish_unpublish_popupbox
  • Vulnerable Versions: <= 6.1.1
  • Root Cause: The function publish_unpublish_popupbox contains a logic error in its nonce verification. Instead of verifying the nonce provided in the user's request (e.g., $_POST['nonce']), it generates a new nonce internally and verifies that newly generated nonce against itself. Since wp_verify_nonce(wp_create_nonce('action'), 'action') always evaluates to true, the security check is effectively bypassed, allowing requests without a valid external nonce to proceed.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: ays_pb_publish_unpublish_popupbox (inferred based on plugin slug ays-popup-box and function name)
  • HTTP Method: POST
  • Parameters:
    • action: ays_pb_publish_unpublish_popupbox (inferred)
    • id: The ID of the popup to modify.
    • status: The target status (e.g., active, inactive, 1, or 0).
  • Authentication: Requires an active Administrator session (exploited via CSRF).
  • Preconditions: At least one popup must exist in the plugin.

3. Code Flow (Inferred)

  1. Entry Point: The plugin registers an AJAX action:
    add_action('wp_ajax_ays_pb_publish_unpublish_popupbox', 'publish_unpublish_popupbox');
  2. Vulnerable Function Call: The publish_unpublish_popupbox() function is triggered.
  3. Flawed Verification:
    public function publish_unpublish_popupbox() {
        // Logic error: creates a nonce and immediately verifies it
        $nonce = wp_create_nonce('ays_pb_nonce'); 
        if (wp_verify_nonce($nonce, 'ays_pb_nonce')) { 
            // The check ALWAYS passes regardless of the request content
            $id = intval($_POST['id']);
            // Code to update popup status in the database...
        }
    }
    
  4. Sink: The status of the popup with the provided id is updated in the database.

4. Nonce Acquisition Strategy

According to the vulnerability description, the nonce implementation is "flawed" because it verifies a "self-created nonce."

Exploitation Note: Because the server verifies a nonce it generates during the request execution rather than one supplied by the attacker, no valid nonce is required from the attacker's side. The request can simply omit the nonce or provide a dummy value.

If, during testing, it is found that a nonce is required (e.g., if the description meant the nonce is simply public), use the following strategy:

  1. Navigate to the Popup Box admin dashboard: /wp-admin/admin.php?page=ays-popup-box.
  2. Extract the nonce from the localized script: browser_eval("window.ays_pb_ajax_obj?.ays_pb_nonce") (inferred variable name based on AYS plugin patterns).

5. Exploitation Strategy

Step 1: Discover Target ID
An attacker would typically guess IDs or view the public site to see popup IDs in the source code. For the PoC, we will create a popup and retrieve its ID.

Step 2: Execute Forged Request
Using the http_request tool (simulating a CSRF where an admin browser sends the request), we will trigger the status change.

  • URL: http://[target]/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body: action=ays_pb_publish_unpublish_popupbox&id=1&status=inactive (inferred parameters)

6. Test Data Setup

  1. Install Plugin: Install and activate ays-popup-box version 6.1.1.
  2. Create Popup: Use WP-CLI to create a dummy popup.
    # AYS Popup Box uses a custom table. We'll use the plugin's UI or a direct DB insert.
    # To be safe, simulate the admin creating a popup via browser:
    # 1. Navigate to /wp-admin/admin.php?page=ays-popup-box-add-new
    # 2. Save a default popup.
    
  3. Verify Initial Status: Confirm the popup is currently "Published" (status active).

7. Expected Results

  1. The admin-ajax.php request will return a success response (likely 1 or a JSON success message).
  2. The popup status in the WordPress database (table wp_ays_pb_popups or similar) will change from active to inactive.
  3. The popup will no longer appear on the frontend of the site.

8. Verification Steps

  1. Check Database via WP-CLI:
    wp db query "SELECT status FROM wp_ays_pb_popups WHERE id=1;"
    
  2. Check Admin UI:
    Navigate to the popups list page and verify the status toggle has changed for the targeted ID.

9. Alternative Approaches

If the status parameter name is different, common alternatives for AYS plugins include:

  • is_checked (0 or 1)
  • active (0 or 1)
  • checked (true or false)

If the AJAX action ays_pb_publish_unpublish_popupbox is incorrect, search the plugin directory for the function name:

grep -r "publish_unpublish_popupbox" /var/www/html/wp-content/plugins/ays-popup-box/

Then identify the associated wp_ajax hook.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Popup Box plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 6.1.1. This is caused by a logic error where the server creates and then immediately verifies its own nonce within the same function, effectively bypassing the intended security check and allowing unauthorized popup status changes.

Vulnerable Code

// In the admin logic of the plugin (likely admin/class-ays-pb-admin.php)
public function publish_unpublish_popupbox() {
    // Flawed logic: creates a nonce and then immediately verifies it against itself
    $nonce = wp_create_nonce('ays_pb_nonce'); 
    if (wp_verify_nonce($nonce, 'ays_pb_nonce')) {
        // This condition is always true, bypassing CSRF protection
        $id = intval($_POST['id']);
        $status = sanitize_text_field($_POST['status']);
        // Database update logic follows...
    }
}

Security Fix

--- a/admin/class-ays-pb-admin.php
+++ b/admin/class-ays-pb-admin.php
@@ -120,8 +120,7 @@
     public function publish_unpublish_popupbox() {
-        $nonce = wp_create_nonce('ays_pb_nonce');
-        if (wp_verify_nonce($nonce, 'ays_pb_nonce')) {
+        if (isset($_POST['nonce']) && wp_verify_nonce($_POST['nonce'], 'ays_pb_nonce')) {
             $id = intval($_POST['id']);
             $status = sanitize_text_field($_POST['status']);

Exploit Outline

The exploit leverages the lack of valid nonce validation to perform a Cross-Site Request Forgery. 1. Target Endpoint: /wp-admin/admin-ajax.php 2. Method: POST 3. Action: ays_pb_publish_unpublish_popupbox 4. Payload Requirements: The attacker needs the ID of a target popup and the desired status (e.g., 'active' or 'inactive'). A typical payload looks like: `action=ays_pb_publish_unpublish_popupbox&id=123&status=inactive`. 5. Execution: The attacker tricks a logged-in site administrator into clicking a link or visiting a malicious page that submits the POST request in the background. Because the server-side code ignores external nonces and validates a self-generated one, the request succeeds without a valid security token from the administrator's session.

Check if your site is affected.

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