[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fZfpSRqTFhQrBS-Wv0ZJ6HALMVAwXx7kXdl8AYURzWT4":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":29,"research_verified":30,"research_rounds_completed":31,"research_plan":32,"research_summary":33,"research_vulnerable_code":34,"research_fix_diff":35,"research_exploit_outline":36,"research_model_used":37,"research_started_at":38,"research_completed_at":39,"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":30,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":30,"source_links":40},"CVE-2026-40784","fluentboards-project-management-task-management-goal-tracking-kanban-board-and-team-collaboration-authenticated-board-me","FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration \u003C= 1.91.2 - Authenticated (Board Member+) Insecure Direct Object Reference","The FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 1.91.2 due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Custom-level access and above, to perform an unauthorized action.","fluent-boards",null,"\u003C=1.91.2","1.91.3","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Authorization Bypass Through User-Controlled Key","2026-04-15 00:00:00","2026-04-21 15:35:14",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F12959cc5-d088-4e2c-8658-e54900839aa6?source=api-prod",7,[22,23,24,25,26,27,28],"app\u002FHttp\u002FControllers\u002FBoardController.php","app\u002FHttp\u002FControllers\u002FCommentController.php","app\u002FHttp\u002FControllers\u002FTaskController.php","app\u002FServices\u002FBoardService.php","app\u002FServices\u002FStageService.php","fluent-boards.php","readme.txt","researched",false,3,"# Research Plan: CVE-2026-40784 FluentBoards IDOR\n\n## 1. Vulnerability Summary\nThe **FluentBoards** plugin (\u003C= 1.91.2) contains an Insecure Direct Object Reference (IDOR) vulnerability in its comment management system. The `CommentController` does not sufficiently validate whether the authenticated user has the authority to modify or delete a specific comment based on its `comment_id`. While the API requires a `board_id` in the URL, it fails to verify if the provided `comment_id` actually belongs to that board or if the user is the author\u002Fadministrator of that comment. This allows any user with \"Board Member\" access (or higher) to modify comments across the entire system by manipulating the ID.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `POST \u002Fwp-json\u002Ffluent-boards\u002Fv1\u002Fboards\u002F{board_id}\u002Fcomments\u002F{comment_id}`\n- **Method:** `POST` (used for updates in the Fluent framework)\n- **Authentication:** Required (User must have at least \"Board Member\" permissions within the plugin).\n- **Vulnerable Parameter:** `{comment_id}` in the REST URL.\n- **Payload Parameter:** `comment` (string) containing the new comment text.\n- **Preconditions:** \n    - The attacker must be logged in.\n    - The attacker must be a member of at least one Board (to access the API).\n    - The attacker needs to know the ID of the comment they wish to modify.\n\n## 3. Code Flow\n1.  **Entry Point:** The request hits the REST API route associated with `CommentController@update`.\n2.  **Controller Logic (`app\u002FHttp\u002FControllers\u002FCommentController.php`):**\n    - The `update` method (truncated in provided source, but visible at line 147) receives `$board_id` and `$comment_id` from the URL.\n    - It calls `$this->commentSanitizeAndValidate()` to process the `comment` body.\n    - It attempts to update the comment via `$this->commentService->update($commentData, $comment_id)`.\n3.  **Missing Check:** There is no logic in the controller to verify:\n    - That the comment identified by `$comment_id` belongs to the board identified by `$board_id`.\n    - That the current user is the owner of the comment or a Board Administrator.\n4.  **Sink:** The database is updated with the new comment content regardless of ownership.\n\n## 4. Nonce Acquisition Strategy\nFluentBoards uses the standard WordPress REST API nonce. It is localized in the admin dashboard.\n\n1.  **Identify Trigger:** The FluentBoards dashboard is located at `\u002Fwp-admin\u002Fadmin.php?page=fluent-boards`.\n2.  **Access Dashboard:** Navigate to the FluentBoards page as the \"Board Member\" user.\n3.  **Extract Nonce:** Use `browser_eval` to extract the nonce from the `window.FluentBoardsAdmin` global object.\n    - **JS Key:** `window.FluentBoardsAdmin.nonce`\n4.  **Alternative:** The standard REST nonce `wp_rest` might also work if passed in the `X-WP-Nonce` header.\n\n## 5. Exploitation Strategy\n### Step 1: Data Gathering\nIdentify the Target Comment ID. For this PoC, we will create a comment as a \"Victim\" user and capture its ID.\n\n### Step 2: Perform the IDOR Update\nUse the `http_request` tool to send a spoofed update request.\n\n- **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-json\u002Ffluent-boards\u002Fv1\u002Fboards\u002F{ATTACKER_BOARD_ID}\u002Fcomments\u002F{VICTIM_COMMENT_ID}`\n- **Method:** `POST`\n- **Headers:**\n    - `Content-Type: application\u002Fjson`\n    - `X-WP-Nonce: {EXTRACTED_NONCE}`\n    - `Cookie: {ATTACKER_SESSION_COOKIES}`\n- **Payload:**\n    ```json\n    {\n      \"comment\": \"This comment has been modified by an unauthorized user.\",\n      \"mentionData\": []\n    }\n    ```\n\n## 6. Test Data Setup\n1.  **Users:**\n    - `victim_user` (Subscriber role)\n    - `attacker_user` (Subscriber role)\n2.  **Boards:**\n    - `Victim Board` (ID: 1): `victim_user` added as \"Admin\".\n    - `Attacker Board` (ID: 2): `attacker_user` added as \"Member\".\n3.  **Content:**\n    - A task created on `Victim Board`.\n    - A comment created by `victim_user` on that task (Target ID: `X`).\n4.  **Plugin Configuration:** Ensure both users are assigned their respective boards via the FluentBoards interface.\n\n## 7. Expected Results\n- The server returns a `200 OK` or `201 Created` response.\n- The response JSON contains the updated comment object with the new description.\n- The comment ID in the response matches `{VICTIM_COMMENT_ID}`.\n\n## 8. Verification Steps\n1.  **Check via CLI:** \n    ```bash\n    wp db query \"SELECT description FROM wp_fboards_comments WHERE id = {VICTIM_COMMENT_ID}\"\n    ```\n2.  **Confirm Content:** Verify the description matches the string: `\"This comment has been modified by an unauthorized user.\"`.\n3.  **Ownership Check:** Verify the `created_by` field in the database remains the `victim_user` ID, proving the comment was modified by someone else.\n\n## 9. Alternative Approaches\n- **IDOR Deletion:** If an `update` vulnerability exists, a `delete` vulnerability often exists at the same level.\n    - **Endpoint:** `DELETE \u002Fwp-json\u002Ffluent-boards\u002Fv1\u002Fboards\u002F{attacker_board_id}\u002Fcomments\u002F{victim_comment_id}`\n- **Board Settings IDOR:** Check if `BoardController::modifyAuthenticationPermission` (line 309 in `BoardService.php` reference) can be triggered by a non-admin by providing a valid `boardId` in a POST request to the settings update endpoint.\n- **Task IDOR:** Attempt to move a task from a victim board to an attacker board by changing the `board_id` and `stage_id` in a task update request. (Check `TaskController.php`).","The FluentBoards plugin is vulnerable to Insecure Direct Object Reference (IDOR) due to insufficient validation that a requested object (such as a task, comment, or stage) actually belongs to the board specified in the API request. This allows authenticated attackers with Board Member access to view, modify, or delete tasks and comments on other boards by manipulating the IDs in the REST API endpoints.","\u002F\u002F app\u002FHttp\u002FControllers\u002FCommentController.php line 212\npublic function deleteComment($board_id, $comment_id)\n{\n    try {\n        $this->commentService->delete($comment_id);\n\n---\n\n\u002F\u002F app\u002FHttp\u002FControllers\u002FTaskController.php line 188\npublic function find($board_id, $task_id)\n{\n    $board_id = absint($board_id);\n    $task_id = absint($task_id);\n    try {\n\n        $stageService = new StageService();\n\n        $task = Task::findOrFail($task_id);\n\n---\n\n\u002F\u002F app\u002FHttp\u002FControllers\u002FCommentController.php line 330\npublic function updateCommentPrivacy($board_id, $comment_id)\n{\n    $comment = Comment::findOrFail($comment_id);\n\n    \u002F\u002F Check if user has permission to update the comment\n    if ($comment->created_by != get_current_user_id()) {","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluent-boards\u002F1.91.2\u002Fapp\u002FHttp\u002FControllers\u002FBoardController.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluent-boards\u002F1.91.3\u002Fapp\u002FHttp\u002FControllers\u002FBoardController.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluent-boards\u002F1.91.2\u002Fapp\u002FHttp\u002FControllers\u002FBoardController.php\t2026-01-26 10:36:14.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluent-boards\u002F1.91.3\u002Fapp\u002FHttp\u002FControllers\u002FBoardController.php\t2026-04-08 13:22:28.000000000 +0000\n@@ -968,7 +968,7 @@\n \n     public function archiveAllTasksInStage($board_id, $stage_id)\n     {\n-        $updates = $this->stageService->archiveAllTasksInStage($stage_id);\n+        $updates = $this->stageService->archiveAllTasksInStage($stage_id, $board_id);\n         return [\n             'message'      => __('Tasks have been archived', 'fluent-boards'),\n             'updatedTasks' => $updates,\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluent-boards\u002F1.91.2\u002Fapp\u002FHttp\u002FControllers\u002FCommentController.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluent-boards\u002F1.91.3\u002Fapp\u002FHttp\u002FControllers\u002FCommentController.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluent-boards\u002F1.91.2\u002Fapp\u002FHttp\u002FControllers\u002FCommentController.php\t2025-12-24 12:28:54.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluent-boards\u002F1.91.3\u002Fapp\u002FHttp\u002FControllers\u002FCommentController.php\t2026-04-08 13:22:28.000000000 +0000\n@@ -27,7 +27,10 @@\n \n     public function getComments(Request $request, $board_id, $task_id)\n     {\n+        $board_id = absint($board_id);\n+        $task_id = absint($task_id);\n         try {\n+            Task::where('board_id', $board_id)->where('id', $task_id)->firstOrFail();\n             $filter = $request->getSafe('filter', 'sanitize_text_field');\n             $per_page =  10;\n \n@@ -105,7 +108,7 @@\n \n             $usersToSendEmail = [];\n             if ($comment->type == 'reply') {\n-                $parentComment = Comment::findOrFail($comment->parent_id);\n+                $parentComment = Comment::where('board_id', (int) $board_id)->where('id', $comment->parent_id)->firstOrFail();\n                 $commenterId = $parentComment->created_by;\n                 if ($commenterId != get_current_user_id())\n                 {\n@@ -212,7 +215,10 @@\n \n     public function deleteComment($board_id, $comment_id)\n     {\n+        $board_id = absint($board_id);\n+        $comment_id = absint($comment_id);\n         try {\n+            Comment::where('board_id', $board_id)->where('id', $comment_id)->firstOrFail();\n             $this->commentService->delete($comment_id);\n \n             return $this->sendSuccess([\n@@ -261,7 +267,10 @@\n \n     public function deleteReply($board_id, $reply_id)\n     {\n+        $board_id = absint($board_id);\n+        $reply_id = absint($reply_id);\n         try {\n+            Comment::where('board_id', $board_id)->where('id', $reply_id)->firstOrFail();\n             $this->commentService->deleteReply($reply_id);\n \n             return $this->sendSuccess([\n@@ -330,7 +339,9 @@\n \n     public function updateCommentPrivacy($board_id, $comment_id)\n     {\n-        $comment = Comment::findOrFail($comment_id);\n+        $board_id = absint($board_id);\n+        $comment_id = absint($comment_id);\n+        $comment = Comment::where('board_id', $board_id)->where('id', $comment_id)->firstOrFail();\n \n         \u002F\u002F Check if user has permission to update the comment\n         if ($comment->created_by != get_current_user_id()) {","The exploit targets the FluentBoards REST API endpoints for comment and task management. \n\n1.  **Authentication**: The attacker must be authenticated and have at least \"Board Member\" permissions on at least one legitimate board.\n2.  **Information Gathering**: The attacker identifies the ID of a task or comment they wish to target (the 'victim' object) that belongs to a board they do not have access to.\n3.  **Request Construction**: The attacker crafts a REST request to a vulnerable endpoint, such as `DELETE \u002Fwp-json\u002Ffluent-boards\u002Fv1\u002Fboards\u002F{ATTACKER_BOARD_ID}\u002Fcomments\u002F{VICTIM_COMMENT_ID}`.\n4.  **Payload Execution**: The attacker includes their valid `X-WP-Nonce` and session cookies. By providing an ID for a board they *do* have access to in the URL path, they bypass the initial authorization check. \n5.  **Impact**: Because the controller logic previously used `findOrFail($comment_id)` or direct service calls without verifying that the `$comment_id` belonged to `$board_id`, the action (delete, update, or view) is performed on the victim's object despite the lack of permission.","gemini-3-flash-preview","2026-04-27 14:42:41","2026-04-27 14:43:13",{"type":41,"vulnerable_version":42,"fixed_version":11,"vulnerable_browse":43,"vulnerable_zip":44,"fixed_browse":45,"fixed_zip":46,"all_tags":47},"plugin","1.91.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ffluent-boards\u002Ftags\u002F1.91.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ffluent-boards.1.91.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ffluent-boards\u002Ftags\u002F1.91.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ffluent-boards.1.91.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ffluent-boards\u002Ftags"]