[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fD_yriyT5R2PSaVYAXhnPOEQadg9tRAaJ_XAilVJcVj8":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-32408","brizy-missing-authorization-2","Brizy \u003C= 2.7.23 - Missing Authorization","The Brizy plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.7.23. This makes it possible for authenticated attackers, with contributor-level access and above, to perform an unauthorized action.","brizy",null,"\u003C=2.7.23","2.7.24","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-02-22 00:00:00","2026-04-15 21:14:19",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F227d81e8-7380-4bc8-8127-046ff87bb4b1?source=api-prod",53,[22,23,24,25,26,27,28,29],"README.md","admin\u002Fabstract-api.php","admin\u002Fblocks\u002Fapi.php","admin\u002Fcloud\u002Fapi.php","admin\u002Ffonts\u002Fapi.php","admin\u002Flayouts\u002Fapi.php","admin\u002Frules\u002Fapi.php","admin\u002Fsymbols\u002Fapi.php","researched",false,3,"# Exploitation Research Plan - CVE-2026-32408 (Brizy \u003C= 2.7.23)\n\n## 1. Vulnerability Summary\nThe Brizy Page Builder plugin for WordPress is vulnerable to **Missing Authorization** in several AJAX API endpoints. The plugin implements an abstract API class `Brizy_Admin_AbstractApi` and multiple subclasses (e.g., `Brizy_Admin_Blocks_Api`, `Brizy_Admin_Fonts_Api`) that register AJAX actions. While these actions verify a WordPress nonce and an editor version string, they fail to perform any capability checks (e.g., `current_user_can()`). This allows authenticated users with Contributor-level access and above to perform administrative actions such as creating, updating, or deleting global blocks, layouts, and custom fonts.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `wp-admin\u002Fadmin-ajax.php`\n- **AJAX Action:** `brizy-delete-saved-block` (or any other action registered in the `Brizy_Admin_*_Api` classes).\n- **HTTP Method:** `POST`\n- **Payload Parameters:**\n    - `action`: `brizy-delete-saved-block` (derived from `Brizy_Editor::prefix()` + `self::DELETE_SAVED_BLOCK_ACTION`)\n    - `hash`: A valid WordPress nonce for the `brizy-api` action.\n    - `version`: The current plugin version (e.g., `2.7.23`).\n    - `uid`: The unique identifier of the block to delete.\n- **Required Authentication:** Contributor level (`PR:L`).\n- **Preconditions:** The attacker must be logged in as a Contributor and have access to the Brizy editor interface (which Contributors have for their own posts) to retrieve the required nonce.\n\n## 3. Code Flow\n1. **Entry Point:** The AJAX action is registered in `admin\u002Fblocks\u002Fapi.php` via `initializeApiActions()`:\n   ```php\n   $pref = 'wp_ajax_' . Brizy_Editor::prefix(); \u002F\u002F prefix is 'brizy'\n   add_action( $pref . self::DELETE_SAVED_BLOCK_ACTION, array( $this, 'actionDeleteSavedBlock' ) );\n   ```\n2. **Abstract Verification:** The handler calls `verifyNonce( self::nonce )` defined in `admin\u002Fabstract-api.php`:\n   ```php\n   protected function verifyNonce( $action ) {\n       $version = $this->param( 'version' );\n       if ( $version !== BRIZY_EDITOR_VERSION ) { ... } \u002F\u002F Checks version match\n       $this->checkNonce( $action ); \u002F\u002F Verifies 'brizy-api' nonce\n   }\n   ```\n3. **Missing Sink:** After `verifyNonce`, the code proceeds directly to the functional logic (e.g., deleting a block via `Brizy_Admin_Blocks_Manager`) without any `current_user_can()` check.\n\n## 4. Nonce Acquisition Strategy\nThe `brizy-api` nonce is required for all API calls. It is localized for the Brizy editor.\n\n1. **Shortcode:** Brizy uses a custom editor interface. Creating a post and clicking \"Edit with Brizy\" loads the necessary scripts.\n2. **Page Creation:** Use WP-CLI to create a post the Contributor can edit.\n   ```bash\n   wp post create --post_type=post --post_title=\"Exploit Page\" --post_status=publish --post_author=[CONTRIBUTOR_ID]\n   ```\n3. **Navigation:** Navigate to the Brizy editor for that post. The URL format is typically: `wp-admin\u002Fpost.php?post=[ID]&action=brizy-edit`.\n4. **Extraction:** Use `browser_eval` to extract the configuration object. Brizy typically stores its configuration in a global JavaScript object named `Brizy` or `BrizyLocal`.\n   - **Target Variable:** `window.brizyEditorConfig?.api?.nonce` or `window.Brizy?.config?.api?.nonce`.\n   - **Version:** The version string is also usually available in the same config object: `window.brizyEditorConfig?.version`.\n\n## 5. Exploitation Strategy\nWe will demonstrate the vulnerability by deleting a \"Saved Block\" created by an Administrator.\n\n1. **Retrieve Target UID:** Use WP-CLI to find a block UID created by the Admin.\n   - Brizy saved blocks are usually in the `brizy_saved_block` post type.\n   - `wp post list --post_type=brizy_saved_block --format=ids`\n   - Get the UID from post meta: `wp post meta get [POST_ID] brizy_post_uid`\n2. **Acquire Nonce:** As a Contributor, visit the editor and extract the `hash` (nonce) and `version`.\n3. **Execute Exploit:** Send a POST request to `admin-ajax.php`.\n\n**Request Details:**\n- **URL:** `http:\u002F\u002F[TARGET]\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method:** `POST`\n- **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body:**\n  ```text\n  action=brizy-delete-saved-block&hash=[NONCE]&version=[VERSION]&uid=[TARGET_UID]\n  ```\n\n## 6. Test Data Setup\n1. **Administrator Actions:**\n   - Create a saved block in Brizy (this generates a `brizy_saved_block` post).\n   - Record the `brizy_post_uid` of this block.\n2. **Contributor User:**\n   - Create a user with the `contributor` role.\n3. **Editor Access:**\n   - Ensure Brizy is enabled for the `post` post type.\n   - Create a post authored by the Contributor.\n\n## 7. Expected Results\n- The AJAX request should return a JSON success response: `{\"success\": true, \"data\": []}`.\n- The `brizy_saved_block` post associated with the target UID should be deleted or moved to trash.\n- Unauthorized users (Contributors) can manipulate global Brizy entities they do not own.\n\n## 8. Verification Steps\n1. **Check Post Existence:** Use WP-CLI to verify the block is gone.\n   ```bash\n   wp post list --post_type=brizy_saved_block --post_author=[ADMIN_ID]\n   ```\n2. **Check Database:** Verify the post with the specific UID no longer exists in `wp_posts` or `wp_postmeta`.\n\n## 9. Alternative Approaches\nIf `delete-saved-block` fails, try **`brizy-create-font`** in `Brizy_Admin_Fonts_Api`:\n- **Action:** `brizy-create-font`\n- **Payload:** Requires `id`, `family`, and `fonts[]` file upload.\n- **Impact:** Allows a Contributor to upload arbitrary files to the `wp-content\u002Fuploads\u002Fbrizy\u002Ffonts` directory, which could lead to further exploitation depending on file handling.\n\nAnother alternative is **`brizy-upload-blocks`** in `Brizy_Admin_Blocks_Api`:\n- **Action:** `brizy-upload-blocks`\n- **Payload:** Requires a ZIP file containing block data.\n- **Impact:** Allows mass creation of global blocks and potentially file uploads via the ZIP extraction process.","The Brizy Page Builder plugin for WordPress is vulnerable to unauthorized access due to missing capability checks in several AJAX API endpoints. This allows authenticated attackers with contributor-level access and above to perform administrative actions such as creating, updating, or deleting global blocks, layouts, and custom fonts.","\u002F\u002F admin\u002Fabstract-api.php line 24\n\tprotected function verifyNonce( $action ) {\n\n\t\t$version = $this->param( 'version' );\n\t\tif ( $version !== BRIZY_EDITOR_VERSION ) {\n\t\t\tBrizy_Logger::instance()->critical( 'Request with invalid editor version',\n\t\t\t\t[\n\t\t\t\t\teditorVersion'   => BRIZY_EDITOR_VERSION,\n\t\t\t\t\t'providedVersion' => $version\n\t\t\t\t] );\n\n\t\t\t$this->error( 400, \"Invalid editor version. Please refresh the page and try again\" );\n\t\t}\n\n\t\t$this->checkNonce( $action );\n\t}\n\n---\n\n\u002F\u002F admin\u002Fblocks\u002Fapi.php line 577\n\tpublic function actionDeleteSavedBlock() {\n\t\t$this->verifyNonce( self::nonce );\n\t\tif ( ! current_user_can( 'edit_pages' ) ) {\n\t\t\t$this->error( 403, 'Unauthorized.' );\n\t\t}\n\t\tif ( ! $this->param( 'uid' ) ) {\n\t\t\t$this->error( 400, 'Invalid uid' );\n\t\t}\n\n\t\t$bockManager = new Brizy_Admin_Blocks_Manager( Brizy_Admin_Blocks_Main::CP_SAVED );\n\n\t\ttry {\n\t\t\t$bockManager->deleteEntity( $this->param( 'uid' ) );\n\t\t} catch ( Exception $exception ) {\n\t\t\t$this->error( 400, $exception->getMessage() );\n\t\t}\n\n\t\t$this->success( [] );\n\t}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbrizy\u002F2.7.23\u002Fadmin\u002Fabstract-api.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbrizy\u002F2.7.24\u002Fadmin\u002Fabstract-api.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbrizy\u002F2.7.23\u002Fadmin\u002Fabstract-api.php\t2024-09-17 07:42:50.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbrizy\u002F2.7.24\u002Fadmin\u002Fabstract-api.php\t2026-02-10 07:58:30.000000000 +0000\n@@ -21,7 +21,14 @@\n \t\u002F**\n \t * @param $action\n \t *\u002F\n-\tprotected function verifyNonce( $action ) {\n+\tprotected function verifyUserCanEdit() {\n+\t\tif (!Brizy_Editor_User::is_user_allowed($this->param('post'))) {\n+\t\t\t$this->error( 400, \"You are not allowed to edit this post\" );\n+\t\t}\n+\t}\n+\tprotected function verifyAuthorization( $action ) {\n+\n+\t\t$this->verifyUserCanEdit();\n \n \t\t$version = $this->param( 'version' );\n \t\tif ( $version !== BRIZY_EDITOR_VERSION ) {\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbrizy\u002F2.7.23\u002Fadmin\u002Fblocks\u002Fapi.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbrizy\u002F2.7.24\u002Fadmin\u002Fblocks\u002Fapi.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbrizy\u002F2.7.23\u002Fadmin\u002Fblocks\u002Fapi.php\t2025-07-17 12:40:20.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbrizy\u002F2.7.24\u002Fadmin\u002Fblocks\u002Fapi.php\t2026-02-10 07:58:30.000000000 +0000\n@@ -73,7 +73,7 @@\n \t}\n \n \tpublic function actionDownloadBlocks() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\tif ( ! $this->param( 'uid' ) ) {\n \t\t\t$this->error( 400, 'Invalid block uid param' );\n \t\t}\n@@ -125,7 +125,7 @@\n \n \tpublic function actionUploadBlocks() {\n \t\ttry {\n-\t\t\t$this->verifyNonce( self::nonce );\n+\t\t\t$this->verifyAuthorization( self::nonce );\n \t\t\tif ( ! isset( $_FILES['files'] ) ) {\n \t\t\t\t$this->error( 400, __( 'Invalid block file' ) );\n \t\t\t}\n@@ -164,7 +164,7 @@\n \t}\n \n \tpublic function actionGetGlobalBlocks() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\ttry {\n \t\t\t$fields      = $this->param( 'fields' ) ? $this->param( 'fields' ) : [];\n \t\t\t$bockManager = new Brizy_Admin_Blocks_Manager( Brizy_Admin_Blocks_Main::CP_GLOBAL );\n@@ -180,7 +180,7 @@\n \t}\n \n \tpublic function actionCreateGlobalBlock() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\tif ( ! $this->param( 'uid' ) ) {\n \t\t\t$this->error( 400, 'Invalid uid' );\n \t\t}\n@@ -256,7 +256,7 @@\n \t}\n \n \tpublic function actionUpdateGlobalBlock() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\ttry {\n \n \t\t\tif ( ! $this->param( 'uid' ) ) {\n@@ -343,7 +343,7 @@\n \t}\n \n \tpublic function actionUpdateGlobalBlocks() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\ttry {\n \n \t\t\tif ( ! current_user_can( 'edit_pages' ) ) {\n@@ -436,7 +436,7 @@\n \t}\n \n \tpublic function actionDeleteGlobalBlock() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\tif ( ! current_user_can( 'edit_pages' ) ) {\n \t\t\t$this->error( 403, 'Unauthorized.' );\n \t\t}\n@@ -454,7 +454,7 @@\n \t}\n \n \tpublic function actionGetSavedBlocks() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\ttry {\n \t\t\t$fields      = $this->param( 'fields' ) ? $this->param( 'fields' ) : [];\n \t\t\t$bockManager = new Brizy_Admin_Blocks_Manager( Brizy_Admin_Blocks_Main::CP_SAVED );\n@@ -472,7 +472,7 @@\n \t}\n \n \tpublic function actionGetSavedBlockByUid() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\tif ( ! $this->param( 'uid' ) ) {\n \t\t\t$this->error( 400, 'Invalid uid' );\n \t\t}\n@@ -492,7 +492,7 @@\n \t}\n \n \tpublic function actionCreateSavedBlock() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\tif ( ! current_user_can( 'edit_pages' ) ) {\n \t\t\t$this->error( 403, 'Unauthorized.' );\n \t\t}\n@@ -532,7 +532,7 @@\n \t}\n \n \tpublic function actionUpdateSavedBlock() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\tif ( ! current_user_can( 'edit_pages' ) ) {\n \t\t\t$this->error( 403, 'Unauthorized.' );\n \t\t}\n@@ -578,7 +578,7 @@\n \t}\n \n \tpublic function actionDeleteSavedBlock() {\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\tif ( ! current_user_can( 'edit_pages' ) ) {\n \t\t\t$this->error( 403, 'Unauthorized.' );\n \t\t}\n@@ -604,7 +604,7 @@\n \tpublic function actionUpdateBlockPositions() {\n \n \t\tglobal $wpdb;\n-\t\t$this->verifyNonce( self::nonce );\n+\t\t$this->verifyAuthorization( self::nonce );\n \t\tif ( ! current_user_can( 'edit_pages' ) ) {\n \t\t\t$this->error( 403, 'Unauthorized.' );\n \t\t}","The exploit targets the AJAX endpoints registered by the Brizy plugin which fail to implement authorization checks. \n\n1. Log in as a user with Contributor-level permissions.\n2. Navigate to the Brizy editor for a post the contributor is allowed to edit (e.g., \u002Fwp-admin\u002Fpost.php?post=[ID]&action=brizy-edit) to obtain a valid WordPress nonce for the 'brizy-api' action and the current BRIZY_EDITOR_VERSION string from the localized JavaScript configuration (window.brizyEditorConfig).\n3. Identify a target object UID (such as a Global Block, Saved Block, or Font UID) that should be restricted to administrators.\n4. Send a POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the following parameters: \n   - action: The target Brizy action (e.g., brizy-delete-saved-block or brizy-create-font).\n   - hash: The extracted 'brizy-api' nonce.\n   - version: The current Brizy plugin version.\n   - uid: The identifier of the block or object to manipulate.\n5. Because the vulnerable code only verifies the nonce and version but lacks capability checks (current_user_can), the server will execute the administrative action on behalf of the low-privileged user.","gemini-3-flash-preview","2026-04-19 01:42:09","2026-04-19 01:42:47",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","2.7.23","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbrizy\u002Ftags\u002F2.7.23","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fbrizy.2.7.23.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbrizy\u002Ftags\u002F2.7.24","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fbrizy.2.7.24.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbrizy\u002Ftags"]