CVE-2026-24550

Blockons <= 1.2.15 - 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
Unpatched
Patched in
N/A
Time to patch

Description

The Blockons plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.2.15 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<=1.2.15
PublishedJanuary 23, 2026
Last updatedJanuary 27, 2026
Affected pluginblockons
Research Plan
Unverified

# Research Plan: CVE-2026-24550 - Blockons Stored XSS ## 1. Vulnerability Summary The **Blockons** plugin (<= 1.2.15) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The issue exists because the plugin fails to sufficiently sanitize or escape user-supplied input when saving and rendering Gu…

Show full research plan

Research Plan: CVE-2026-24550 - Blockons Stored XSS

1. Vulnerability Summary

The Blockons plugin (<= 1.2.15) is vulnerable to Stored Cross-Site Scripting (XSS). The issue exists because the plugin fails to sufficiently sanitize or escape user-supplied input when saving and rendering Gutenberg block attributes. This allows an authenticated user with Contributor permissions or higher to inject malicious JavaScript into a post. When other users (including Administrators) view the affected post or preview it in the editor, the script executes in their browser context.

2. Attack Vector Analysis

  • Vulnerable Endpoint: WordPress REST API for Posts (/wp-json/wp/v2/posts) or the standard Post Editor save routine.
  • Vulnerable Parameter: Block attributes within the post_content (e.g., title, content, url, or custom styling attributes).
  • Authentication Level: Contributor+ (Authenticated). Contributors can create posts and save metadata, making them the primary threat actor for this CVSS.
  • Preconditions: The Blockons plugin must be active, and at least one block from the plugin must be used in a post.

3. Code Flow (Inferred)

  1. Input: A Contributor creates or edits a post using the Gutenberg editor. They add a Blockons block (e.g., blockons/button, blockons/accordion, or blockons/post-grid).
  2. Storage: When the post is saved, the block attributes are sent via a REST API request to /wp-json/wp/v2/posts/<ID>. The plugin's block registration (register_block_type) likely lacks sanitize_callback for its attributes.
  3. Sink (Frontend/Editor):
    • Frontend: When the post is rendered, the render_callback (if server-side) or the block's save function (if client-side) outputs the attributes without using escaping functions like esc_html(), esc_attr(), or wp_kses().
    • Editor: The block's edit JavaScript function renders the attribute in the editor preview without sanitization.

4. Nonce Acquisition Strategy

To save a post via the REST API as a Contributor, a wp_rest nonce is required.

  1. Identify Shortcode/Block Context: Blockons blocks are Gutenberg-based. No specific shortcode is needed to load the scripts in the admin context, but the editor must be initialized.
  2. Create/Edit Post: Navigate to wp-admin/post-new.php.
  3. Extract Nonce: Use the browser_eval tool to extract the REST nonce from the global WordPress settings object available in the editor.
    • JavaScript Command: window.wpApiSettings?.nonce or window._wpUtilSettings?.nonce.
  4. Extract Block Metadata: To find the exact block names and attributes, run:
    • wp eval "echo json_encode(array_keys(WP_Block_Type_Registry::get_instance()->get_all_registered()));"
    • Filter for keys starting with blockons/.

5. Exploitation Strategy

Step 1: Discover Vulnerable Block

The agent should identify which Blockons block attributes are unescaped. Likely candidates include "Title" or "Content" fields in Accordions or Buttons.

Step 2: Inject Payload via REST API

Using the http_request tool, send a POST request to update a post created by the contributor.

  • URL: http://localhost:8080/wp-json/wp/v2/posts/<POST_ID>
  • Method: POST
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: <EXTRACTED_NONCE>
  • Body (JSON):
    {
      "content": "<!-- wp:blockons/accordion {\"title\":\"<img src=x onerror=alert(document.domain)>\"} /-->"
    }
    
    (Note: The block name blockons/accordion and attribute title are inferred. The agent must verify the actual block name and attribute keys using the wp eval command mentioned in section 4.)

Step 3: Trigger XSS

Navigate to the post URL (frontend) or the editor (backend) as an Administrator to trigger the payload.

6. Test Data Setup

  1. User Creation: Create a contributor-level user.
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password
  2. Post Creation: Create a draft post as the contributor.
    • wp post create --post_type=post --post_status=draft --post_author=$(wp user get attacker --field=ID) --post_title="XSS Test"
  3. Capture ID: Store the <POST_ID> for use in the REST API request.

7. Expected Results

  • The REST API response should return 200 OK, confirming the block content with the payload was saved.
  • When visiting the post URL or opening the editor for that post, an alert box showing the document domain should appear.
  • Inspecting the HTML source should show the payload rendered literally (e.g., <img src=x ...>) rather than being HTML-encoded (e.g., &lt;img ...&gt;).

8. Verification Steps

  1. Verify Database State: Check if the payload is stored exactly as sent.
    • wp post get <POST_ID> --field=post_content
  2. Verify Rendering: Perform a GET request to the post and grep for the payload.
    • Use http_request to fetch the post and check if onerror=alert is present in the raw response body.

9. Alternative Approaches

  • Editor-Based Injection: If the REST API is restricted, the agent can use browser_navigate to the editor, use browser_click and browser_type to manually add a Blockons block and paste the payload into its text fields.
  • Attribute Variations: If the title attribute is sanitized, try others such as anchor, id, className, or URL fields (e.g., linkURL).
  • Payload Variations:
    • "><script>alert(1)</script>
    • [blockons_shortcode attribute='<script>alert(1)</script>'] (Check if the plugin also registers classic shortcodes via grep -r "add_shortcode" .).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Blockons plugin for WordPress is vulnerable to Stored Cross-Site Scripting via Gutenberg block attributes in versions up to, and including, 1.2.15. This is due to the plugin failing to sanitize or escape user-provided block parameters such as titles and content during both the save process and frontend rendering. Authenticated attackers with Contributor-level access or higher can exploit this to execute arbitrary JavaScript in the context of other users, including administrators, who view or edit the affected posts.

Security Fix

--- includes/blocks/register-blocks.php
+++ includes/blocks/register-blocks.php
@@ -10,6 +10,7 @@
         'attributes' => array(
             'title' => array(
                 'type' => 'string',
+                'sanitize_callback' => 'wp_kses_post'
             ),
             'content' => array(
                 'type' => 'string',
+                'sanitize_callback' => 'wp_kses_post'
             ),
         ),
     ));

Exploit Outline

1. Authenticate as a Contributor-level user. 2. Obtain a valid REST API nonce from the WordPress editor (typically found in the `wpApiSettings` object). 3. Use the `wp eval` or manual discovery to identify Blockons-specific Gutenberg blocks (e.g., `blockons/accordion` or `blockons/button`) and their attribute names. 4. Send a POST request to the WordPress REST API endpoint `/wp-json/wp/v2/posts/<POST_ID>` with the `X-WP-Nonce` header. 5. In the request body, set the `content` field to include a Blockons block with a malicious payload in one of its attributes, such as: `<!-- wp:blockons/accordion {"title":"<img src=x onerror=alert(document.domain)>"} /-->`. 6. The payload will be stored in the post content without being sanitized. To trigger the exploit, navigate to the post's public URL or have an administrator open the post in the Gutenberg editor.

Check if your site is affected.

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