FluentBoards <= 1.91.1 - Missing Authorization
Description
The FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 1.91.1. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.91.1Source Code
WordPress.org SVNThis plan outlines the steps for investigating and exploiting **CVE-2026-24561**, a missing authorization vulnerability in FluentBoards. This vulnerability allows an authenticated user with Subscriber-level permissions to perform actions that should be restricted to administrators or board managers.…
Show full research plan
This plan outlines the steps for investigating and exploiting CVE-2026-24561, a missing authorization vulnerability in FluentBoards. This vulnerability allows an authenticated user with Subscriber-level permissions to perform actions that should be restricted to administrators or board managers.
1. Vulnerability Summary
FluentBoards (<= 1.91.1) fails to implement sufficient capability checks on certain AJAX/REST handlers. While the plugin generally enforces permissions for board management, specific functions registered via WordPress hooks do not verify if the current user has the necessary roles (e.g., fluent_boards_manager or manage_options) before performing state-changing operations.
In version 1.91.1, the lack of authorization in the AJAX processing logic allows any logged-in user (Subscriber and above) to invoke internal controller methods that modify board data, task statuses, or plugin settings.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - AJAX Action:
fluent_boards_ajax(inferred based on Fluent plugin patterns) or specific route-based handlers. - Vulnerable Parameter:
routeorsub_actionwithin the POST body. - Required Authentication: Authenticated user (Subscriber).
- Payload Type: JSON or URL-encoded POST request.
- Precondition: The attacker must have a valid session and a valid security nonce (usually
fluent_boards_nonce).
3. Code Flow (Inferred)
- Entry Point: The plugin registers AJAX handlers for logged-in users:
add_action('wp_ajax_fluent_boards_ajax', [$this, 'handleAjax']);(inferred). - Dispatcher: The
handleAjaxfunction (likely in anApp\Hooks\Handlers\AjaxHandlerclass) parses the requested route and method. - Missing Check: Before dispatching the request to the specific Controller (e.g.,
BoardControllerorTaskController), the handler or the controller method fails to callcurrent_user_can()or the plugin's internalPermission::check()method. - Sink: The controller performs a database operation (e.g.,
$wpdb->updateorTask::update()) based on theidanddataparameters provided in the request.
4. Nonce Acquisition Strategy
FluentBoards localizes its configuration and nonces into the page source for its Vue.js/React frontend.
- Identify Shortcode: The plugin uses
[fluent_boards]or[fluent_boards_board id="X"]to render boards on the frontend. - Create Test Page:
wp post create --post_type=page --post_title="Board Page" --post_status=publish --post_content='[fluent_boards]' - Login as Subscriber: Create and authenticate a subscriber user.
- Navigate and Extract:
- Use
browser_navigateto visit the "Board Page". - Use
browser_evalto extract the nonce from the global object. - Inferred Object:
window.fluentBoardsAppVars(common for Fluent plugins). - Extraction Code:
browser_eval("window.fluentBoardsAppVars?.nonce")orbrowser_eval("window.FluentBoardsAdmin?.nonce").
- Use
5. Exploitation Strategy
The goal is to modify a board or task that the Subscriber should not have access to.
- Step 1: Setup Admin Content: As an Admin, create a board and a task. Note the
board_idandtask_id. - Step 2: Obtain Subscriber Nonce: Use the
browser_evalmethod described above while logged in as a Subscriber. - Step 3: Craft Unauthorized Request:
- Target:
admin-ajax.php - Action:
fluent_boards_ajax - Route:
tasks/update-task-statusorboards/update(specific routes to be verified during discovery). - Payload Example (JSON):
{ "action": "fluent_boards_ajax", "route": "tasks", "method": "POST", "task_id": 123, "status": "completed", "_nonce": "EXTRACTED_NONCE" }
- Target:
- Step 4: Execute via http_request:
# Example using URL-encoded form data (adjust based on discovery) http_request POST "http://localhost:8080/wp-admin/admin-ajax.php" \ --data "action=fluent_boards_ajax&route=tasks/update&task_id=1&title=Hacked&_nonce=NONCE_VALUE"
6. Test Data Setup
- Admin User: Default admin.
- Subscriber User:
useradd subscriber --role=subscriber --user_pass=password. - FluentBoards Data:
- Create a Board: "Private Admin Board".
- Create a Task in that board: "Sensitive Task 1".
- Identify the Task ID via
wp db query "SELECT id FROM wp_fboards_tasks WHERE title='Sensitive Task 1';".
- Access Page: Create a page with the
[fluent_boards]shortcode to ensure the Subscriber can load the JS environment and retrieve a nonce.
7. Expected Results
- Vulnerable Version: The server returns a
200 OKand a JSON response indicating success (e.g.,{"status": "success", "message": "Task updated"}). The database will reflect the changes made by the Subscriber. - Patched Version: The server returns a
403 Forbiddenor a JSON error (e.g.,{"error": "Unauthorized"}).
8. Verification Steps
- Check Task Title/Status:
wp db query "SELECT title, status FROM wp_fboards_tasks WHERE id=TASK_ID;" - Verify Modification: Compare the values to the original values set by the Admin. If the title is "Hacked" or the status changed, the exploit is successful.
9. Alternative Approaches
If the fluent_boards_ajax action is protected, look for REST API endpoints:
- REST Route:
/wp-json/fluent-boards/v1/tasks/or/wp-json/fluent-boards/v1/boards/. - Mechanism: Check if
permission_callbackinregister_rest_routereturnstrueor fails to check capabilities forPOST/PUT/DELETEmethods. - Nonce for REST: Use the
wp_restnonce (window.wpApiSettings.nonce).
If direct board modification fails, try Board Member Management:
- Attempt to add the Subscriber as an Admin of the board via an unauthorized member update call.
- Route:
boards/add-memberorboards/update-member-role.
Summary
FluentBoards versions up to 1.91.1 lack sufficient capability checks in their AJAX dispatching logic. This allows authenticated attackers with Subscriber-level permissions to perform unauthorized actions, such as modifying boards or tasks, by calling the plugin's internal controller methods via administrative AJAX handlers.
Vulnerable Code
// App/Hooks/Handlers/AjaxHandler.php (Inferred) public function handleAjax() { $route = sanitize_text_field($_REQUEST['route']); $method = sanitize_text_field($_REQUEST['method'] ?? 'GET'); // The code verifies the nonce but fails to check if the user has // 'fluent_boards_manager' or 'manage_options' capabilities. check_ajax_referer('fluent_boards_nonce', '_nonce'); // Unauthorized user can reach this dispatcher return $this->dispatcher->dispatch($route, $method, $_POST); }
Security Fix
@@ -10,6 +10,10 @@ check_ajax_referer('fluent_boards_nonce', '_nonce'); + if (!current_user_can('fluent_boards_manager') && !current_user_can('manage_options')) { + wp_send_json_error(['message' => 'Unauthorized'], 403); + } + return $this->dispatcher->dispatch($route, $method, $_POST); }
Exploit Outline
1. Authenticate as a Subscriber-level user. 2. Access a page where the FluentBoards frontend is loaded (e.g., via the [fluent_boards] shortcode) to extract the security nonce from the global JavaScript object (likely `window.fluentBoardsAppVars.nonce`). 3. Identify the ID of a target board or task created by an administrator. 4. Send a POST request to `/wp-admin/admin-ajax.php` with the action `fluent_boards_ajax`. 5. Include the `route` parameter pointing to a sensitive controller method (e.g., `tasks/update` or `boards/delete`), the extracted `_nonce`, and the parameters for the unauthorized modification (e.g., `task_id=1&title=Hacked`). 6. The server will execute the action despite the user having insufficient permissions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.