[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fgVjNKLFPH6LFQZz8LI6UO9sLg_-asmapQaKF5n9vEGQ":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-5395","fluent-forms-authenticated-subscriber-authorization-bypass-via-table-parameter","Fluent Forms \u003C= 6.2.0 - Authenticated (Subscriber+) Authorization Bypass via 'table' Parameter","The Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 6.2.0 via the exportEntries function due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Fluent Forms manager-level access and above, to bypass form-level access restrictions to access submissions from forms they are not authorized to view, export data from arbitrary database tables, and enumerate database table names via error message disclosure.","fluentform",null,"\u003C=6.2.0","6.2.1","high",8.2,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:H\u002FI:L\u002FA:N","Authorization Bypass Through User-Controlled Key","2026-05-13 18:08:24","2026-05-14 06:44:12",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F9cd12b8a-2033-4236-abcd-2a8d08e7f099?source=api-prod",1,[22,23,24,25,26,27,28,29],"app\u002FApi\u002FForm.php","app\u002FHelpers\u002FProtector.php","app\u002FHelpers\u002FTraits\u002FGlobalDefaultMessages.php","app\u002FHooks\u002FAjax.php","app\u002FHooks\u002Ffilters.php","app\u002FHttp\u002FControllers\u002FFormController.php","app\u002FHttp\u002FControllers\u002FFormIntegrationController.php","app\u002FHttp\u002FControllers\u002FFormSettingsController.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-5395 (Fluent Forms Authorization Bypass)\n\n## 1. Vulnerability Summary\nThe **Fluent Forms** plugin (up to version 6.2.0) contains an **Insecure Direct Object Reference (IDOR)** vulnerability in its entry export functionality. The AJAX action `fluentform-form-entries-export` invokes the `exportEntries` method in the `Transfer` module. This function fails to validate a user-supplied `table` parameter. \n\nWhile the intended use is to export submissions from the `wp_fluentform_submissions` table for a specific form, an attacker with \"Entries Viewer\" permissions (which can be granted to low-privileged roles like Subscribers via the plugin's \"Managers\" settings) can manipulate the `table` parameter to export data from **arbitrary database tables** (e.g., `wp_users`, `wp_options`) or enumerate table names via database error messages.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action**: `fluentform-form-entries-export`\n- **Authentication**: Authenticated (Subscriber+ with \"Entries Viewer\" or \"Manager\" permissions).\n- **Vulnerable Parameter**: `table`\n- **Payload**: The name of a sensitive database table (e.g., `wp_users`).\n\n## 3. Code Flow\n1. **Entry Point**: In `app\u002FHooks\u002FAjax.php`, the action is registered:\n   ```php\n   $app->addAction('wp_ajax_fluentform-form-entries-export', function () use ($app) {\n       Acl::verify('fluentform_entries_viewer'); \u002F\u002F Check for viewer capability\n       (new \\FluentForm\\App\\Modules\\Transfer\\Transfer())->exportEntries();\n   });\n   ```\n2. **Authorization**: `Acl::verify('fluentform_entries_viewer')` checks if the current user has the permission to view entries. This can be assigned to any role in the Fluent Forms global settings.\n3. **Sink**: The `exportEntries()` function (in `app\u002FModules\u002FTransfer\u002FTransfer.php`, inferred from the hook) reads the `table` parameter from the request. It likely uses this parameter to construct a SQL query or initialize a Database Model without verifying that the table name is restricted to submission-related tables.\n4. **Execution**: The plugin executes a `SELECT *` (or similar) on the provided `table` and generates a downloadable file (CSV\u002FJSON).\n\n## 4. Nonce Acquisition Strategy\nThe `Acl::verify` call in Fluent Forms typically validates the `_fluent_form_nonce`. This nonce is localized into the WordPress admin dashboard.\n\n### Strategy:\n1. **Setup**: Create a subscriber user and ensure they have the `fluentform_entries_viewer` permission.\n2. **Page Navigation**: Navigate to the Fluent Forms \"Entries\" page.\n3. **Nonce Extraction**:\n   - The nonce is usually stored in the `fluent_forms_global_var` JavaScript object.\n   - Use `browser_eval` to extract it: `window.fluent_forms_global_var?.nonce`.\n\n## 5. Exploitation Strategy\n### Step 1: Elevate Subscriber Permissions\nFluent Forms allows custom managers. We will use WP-CLI to configure the plugin to allow Subscribers to view entries, simulating a common administrative delegation.\n```bash\n# Set the global settings to allow 'subscriber' role to have 'fluentform_entries_viewer' capability\n# This is a conceptual CLI command; the actual option key is _fluentform_global_form_settings\nwp option patch update _fluentform_global_form_settings managers '{\"subscriber\":{\"capabilities\":[\"fluentform_entries_viewer\"]}}'\n```\n\n### Step 2: Obtain Nonce as Subscriber\nLog in as the Subscriber and navigate to the admin dashboard.\n1. `browser_navigate(\"\u002Fwp-admin\u002Fadmin.php?page=fluent_forms\")`\n2. `NONCE = browser_eval(\"window.fluent_forms_global_var.nonce\")`\n\n### Step 3: Trigger the Vulnerable Export\nSend a POST request to `admin-ajax.php` targeting the `wp_users` table.\n\n- **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method**: `POST`\n- **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body**:\n  ```\n  action=fluentform-form-entries-export&\n  table=wp_users&\n  form_id=1&\n  _fluent_form_nonce=[NONCE]\n  ```\n\n### Step 4: Enumeration (Alternative)\nTo enumerate tables, provide a non-existent table name (e.g., `table=non_existent_xyz`) and check if the response body contains a SQL error message disclose by the database.\n\n## 6. Test Data Setup\n1. **Create a Form**: `wp fluentform create --title=\"Test Form\"`\n2. **Create a Submission**: Submit at least one entry to the form so the \"Entries\" menu is accessible.\n3. **Create User**: `wp user create attacker attacker@example.com --role=subscriber --user_pass=password`\n4. **Configure Permissions**: Ensure the Subscriber role is added to the Fluent Forms \"Managers\" list with \"Entries Viewer\" permissions.\n\n## 7. Expected Results\n- **Success**: The response will be a file download (likely CSV format) containing the contents of the `wp_users` table, including `user_login`, `user_pass` (hashes), and `user_email`.\n- **Enumeration**: If an invalid table is provided, the plugin may return a JSON error or raw HTML containing a database error string like `Table 'wordpress.non_existent_xyz' doesn't exist`.\n\n## 8. Verification Steps\n1. **File Content**: Verify the downloaded content contains the string `admin` and a WordPress password hash (starting with `$P$B`).\n2. **CLI Check**: Verify the current user's meta to see if Fluent Forms added specific manager metadata:\n   `wp user meta get [ID] _fluentform_manager_capabilities`\n\n## 9. Alternative Approaches\n- **Table Brute-forcing**: If error disclosure is enabled, iterate through common table prefixes (e.g., `wp_`, `wp_2_`, `staging_`) and table names.\n- **Form ID Bypass**: If the attacker is authorized for Form ID 1 but not Form ID 2, they can try to set `table=wp_fluentform_submissions` and provide a `form_id=2` filter to see if the table-level access overrides the form-level ownership check.\n- **Information Leak via JSON**: Check if the response is JSON instead of CSV by adding `format=json` to the POST body.","Fluent Forms is vulnerable to an Insecure Direct Object Reference (IDOR) in its entry export functionality due to missing validation on the 'table' parameter. Authenticated attackers with 'Entries Viewer' or 'Manager' permissions (which can be assigned to low-privileged roles like Subscribers) can exploit this to export sensitive data from arbitrary database tables (e.g., wp_users) or view submissions from forms they are not authorized to access.","\u002F\u002F app\u002FHooks\u002FAjax.php:105 (v6.2.0)\n$app->addAction('wp_ajax_fluentform-form-entries-export', function () use ($app) {\n    Acl::verify('fluentform_entries_viewer');\n    (new \\FluentForm\\App\\Modules\\Transfer\\Transfer())->exportEntries();\n});","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluentform\u002F6.2.0\u002Fapp\u002FHooks\u002FAjax.php\t2026-04-01 13:33:54.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Ffluentform\u002F6.2.1\u002Fapp\u002FHooks\u002FAjax.php\t2026-04-16 11:38:36.000000000 +0000\n@@ -101,8 +113,11 @@\n \n \n \n $app->addAction('wp_ajax_fluentform-form-entries-export', function () use ($app) {\n-    Acl::verify('fluentform_entries_viewer');\n+    $formId = Acl::verifyFormId($app->request->get('form_id'));\n+\n+    Acl::verify('fluentform_entries_viewer', $formId);\n     (new \\FluentForm\\App\\Modules\\Transfer\\Transfer())->exportEntries();\n });","The exploit requires an authenticated session with a user role that has been granted 'Entries Viewer' permissions in the Fluent Forms Global Settings (Managers section). \n\n1. Log in to the WordPress dashboard as a user with the required permissions.\n2. Access any form entries page to extract the `_fluent_form_nonce` from the `window.fluent_forms_global_var.nonce` JavaScript object.\n3. Send a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php` with the following parameters:\n   - `action`: `fluentform-form-entries-export`\n   - `_fluent_form_nonce`: [EXTRACTED_NONCE]\n   - `table`: The name of a target database table (e.g., `wp_users`).\n   - `form_id`: A valid form ID (this bypasses the initial ACL check, but the underlying logic fails to restrict the 'table' parameter to that specific form's submission table).\n4. The plugin will execute a query against the user-supplied table and return a CSV\u002FJSON file containing the table's data.","gemini-3-flash-preview","2026-05-14 17:04:04","2026-05-14 17:04:42",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","6.2.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ffluentform\u002Ftags\u002F6.2.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ffluentform.6.2.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ffluentform\u002Ftags\u002F6.2.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Ffluentform.6.2.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Ffluentform\u002Ftags"]