Breeze <= 2.2.21 - Missing Authorization
Description
The Breeze Cache plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.2.21. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-69364 (Breeze Cache) ## 1. Vulnerability Summary Breeze Cache (up to 2.2.21) contains a **Missing Authorization** vulnerability. The plugin registers administrative actions (such as purging the cache) that are either hooked to `admin_init` or registered as `wp…
Show full research plan
Exploitation Research Plan: CVE-2025-69364 (Breeze Cache)
1. Vulnerability Summary
Breeze Cache (up to 2.2.21) contains a Missing Authorization vulnerability. The plugin registers administrative actions (such as purging the cache) that are either hooked to admin_init or registered as wp_ajax_nopriv actions without a corresponding current_user_can('manage_options') check. This allows unauthenticated attackers to trigger sensitive cache-clearing operations, potentially impacting site performance or bypassing caching layers.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Method:
GETorPOST - Vulnerable Action:
breeze_clear_all_cacheorbreeze_clear_varnish_cache(inferred from plugin features). - Authentication: None required (unauthenticated).
- Precondition: The Breeze plugin must be active.
The vulnerability typically resides in how the plugin handles "manual" cache purges triggered via the WordPress Admin Bar or settings page. If these handlers are hooked to admin_init and only check for the presence of a $_GET['action'] parameter without a capability check, any user can reach them by calling admin-ajax.php, which initializes the admin environment for all users.
3. Code Flow
- Entry Point: The attacker sends a request to
/wp-admin/admin-ajax.php?action=breeze_clear_all_cache. - Hook Execution: WordPress core loads and triggers
admin_init. - Vulnerable Class:
Breeze_Admin(ininc/admin/class-breeze-admin.php). - Vulnerable Method:
breeze_clear_cache_all_manualor a similar method hooked toadmin_init. - Logic:
- The method checks
if ( isset( $_GET['action'] ) && $_GET['action'] === 'breeze_clear_all_cache' ). - It fails to call
current_user_can( 'manage_options' ). - It fails to call
check_admin_referer()(nonce check).
- The method checks
- Sink: The plugin calls
Breeze_Purge::purge_all()orbreeze_clean_cache_folder(), deleting all files inwp-content/cache/breeze/.
4. Nonce Acquisition Strategy
If the vulnerability is a missing authorization check in an admin_init handler, it often also lacks a nonce check (CSRF).
However, if the plugin uses a standard AJAX handler:
- Identify Script Handle: Look for
wp_localize_scriptininc/admin/class-breeze-admin.php. The handle is likelybreeze-admin-js. - Identify Variable: The localization variable is usually
breeze_admin_objorbreeze_helper. - Extraction:
- Since
breeze-admin-jsusually only loads for logged-in admins, check if there is a frontend equivalent likebreeze-prefetch-js. - If no script is found on the frontend, check if the nonce is required. If the action is truly unauthenticated (
wp_ajax_nopriv), the nonce must be leaked on the frontend. - Use
browser_navigateto the homepage. - Use
browser_evalto search for nonces:browser_eval("window.breeze_admin_obj?.nonce").
- Since
Note: If the vulnerability is in an admin_init hook triggered via a GET parameter, no nonce is usually required.
5. Exploitation Strategy
We will attempt to trigger a full cache purge unauthenticated.
- Step 1: Confirm Cache Existence: Generate cache by visiting the site and confirm the directory exists and contains files.
- Step 2: Trigger Purge: Send a request to the AJAX endpoint.
- Request:
GET /wp-admin/admin-ajax.php?action=breeze_clear_all_cache HTTP/1.1 Host: target.local
- Request:
- Step 3: Alternative Trigger (if GET fails): Try POSTing.
- Request:
POST /wp-admin/admin-ajax.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded action=breeze_clear_all_cache
- Request:
- Step 4: Check for other actions: If the above fails, try:
action=breeze_clear_varnish_cacheaction=breeze_purge_cache
6. Test Data Setup
- Install Plugin:
wp plugin install breeze --version=2.2.21 --activate - Configure Breeze:
- Enable "Internal Browser Caching" and "Desktop Cache".
wp option update breeze_configuration '{"breeze-desktop-cache":"1","breeze-browser-cache":"1"}' --format=json
- Populate Cache:
- Use the
http_requesttool to visit the homepage and several posts at least twice. - Confirm cache files exist:
ls -R /var/www/html/wp-content/cache/breeze/.
- Use the
7. Expected Results
- The server returns a
200 OKor302 Redirect. - The response might contain a success message or JSON:
{"success":true}. - Most importantly: the files previously seen in
/var/www/html/wp-content/cache/breeze/will be deleted.
8. Verification Steps
- Check Filesystem: Run
ls -R /var/www/html/wp-content/cache/breeze/and verify the directory is empty or the specific site cache folder has been deleted. - Check Logs: If
WP_DEBUGis enabled, check for calls toBreeze_Purge. - WP-CLI Verification:
wp eval "echo count(glob('/var/www/html/wp-content/cache/breeze/*'));"should return0.
9. Alternative Approaches
If admin-ajax.php does not trigger the vulnerability:
- Direct Admin Access: Try
GET /wp-admin/index.php?action=breeze_clear_all_cache. Even if it redirects to login, theadmin_inithook may have already fired. - REST API: Check if Breeze registers any REST routes in
inc/cache/class-breeze-rest.phpwithout apermission_callback.GET /wp-json/breeze/v1/purge
- Varnish Specifics: If Varnish is enabled in settings, the
breeze_clear_varnish_cacheaction may be more likely to be exposed.
Summary
The Breeze Cache plugin for WordPress is vulnerable to unauthorized cache purging due to missing capability and nonce checks in its administrative initialization hooks. This allows unauthenticated attackers to clear the site's entire cache by sending a crafted request to common administrative endpoints.
Vulnerable Code
// inc/admin/class-breeze-admin.php add_action( 'admin_init', array( $this, 'breeze_clear_cache_all_manual' ) ); public function breeze_clear_cache_all_manual() { if ( isset( $_GET['action'] ) && $_GET['action'] === 'breeze_clear_all_cache' ) { // Missing current_user_can( 'manage_options' ) check // Missing check_admin_referer( ... ) check Breeze_Purge::purge_all(); wp_redirect( wp_get_referer() ); exit; } }
Security Fix
@@ -100,6 +100,11 @@ public function breeze_clear_cache_all_manual() { if ( isset( $_GET['action'] ) && $_GET['action'] === 'breeze_clear_all_cache' ) { + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + check_admin_referer( 'breeze_purge_action' ); Breeze_Purge::purge_all(); wp_redirect( wp_get_referer() ); exit;
Exploit Outline
The exploit involves sending an unauthenticated HTTP request to the WordPress admin environment to trigger the 'admin_init' hook. Because the plugin processes the 'breeze_clear_all_cache' action within this hook without verifying the user's role or checking for a valid CSRF nonce, an attacker can purge the cache remotely. 1. Identify a site running Breeze Cache <= 2.2.21. 2. Send a GET or POST request to `/wp-admin/admin-ajax.php?action=breeze_clear_all_cache`. 3. The server processes the request, initializes the admin environment, triggers the vulnerable hook, and executes the cache purge logic (e.g., deleting files in wp-content/cache/breeze/). 4. Verify the cache is cleared by checking the filesystem or observing performance degradation on the next page load.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.