CVE-2026-8701

GNTT Post Title Ticker <= 1.0 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes

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 GNTT Post Title Ticker plugin for WordPress is vulnerable to Stored Cross-Site Scripting in version 1.0 via the `title-ticker-slide`, `title-ticker-fade`, and `title-ticker-typing` shortcodes. This is due to insufficient input sanitization and output escaping on shortcode attributes (notably `border`, `width`, `height`, `header_background`, `header_text_color`, and `id`) within the `gntt_title_ticker_slide()`, `gntt_title_ticker_fade()`, and `gntt_title_ticker_typing()` functions. None of these attribute values are passed through `esc_attr()` or any other escaping function before being concatenated into HTML output. 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.0
PublishedMay 26, 2026
Last updatedMay 27, 2026
Affected plugingntt-post-title-ticker
Research Plan
Unverified

This research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the **GNTT Post Title Ticker** plugin. ### 1. Vulnerability Summary * **ID:** CVE-2026-8701 * **Vulnerability Type:** Stored Cross-Site Scripting (XSS) * **Component:** GNTT Po…

Show full research plan

This research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the GNTT Post Title Ticker plugin.

1. Vulnerability Summary

  • ID: CVE-2026-8701
  • Vulnerability Type: Stored Cross-Site Scripting (XSS)
  • Component: GNTT Post Title Ticker (<= 1.0)
  • Vulnerable Functions: gntt_title_ticker_slide(), gntt_title_ticker_fade(), and gntt_title_ticker_typing().
  • Vulnerable Attributes: border, width, height, header_background, header_text_color, and id.
  • Cause: Shortcode attributes are concatenated directly into HTML output without being passed through escaping functions like esc_attr() or esc_html(). This allows a user with Contributor-level privileges (who can use shortcodes) to inject malicious scripts into pages.

2. Attack Vector Analysis

  • Entry Point: Shortcode injection within a Post or Page content.
  • Shortcodes: [title-ticker-slide], [title-ticker-fade], or [title-ticker-typing].
  • Vulnerable Parameter: Attributes within the shortcode (e.g., id, width).
  • Authentication: Requires a user with at least Contributor privileges (capability edit_posts).
  • Preconditions: The plugin must be active.

3. Code Flow (Inferred from Description)

  1. Registration: The plugin registers shortcodes via add_shortcode() (likely in the main plugin file or an init hook).
  2. Trigger: A user with edit_posts capability creates a post containing a shortcode like [title-ticker-slide width='"><script>alert(1)</script>'].
  3. Parsing: When the post is viewed, WordPress calls the associated callback function, e.g., gntt_title_ticker_slide($atts).
  4. Processing: Inside the callback, the plugin extracts attributes. It likely uses shortcode_atts() to merge user input with defaults.
  5. Sink: The code constructs an HTML string for output. Because it omits esc_attr(), it produces:
    <div width=""><script>alert(1)</script>" ... >
  6. Execution: The unescaped payload is rendered in the frontend, executing the script in the context of any user viewing the page.

4. Nonce Acquisition Strategy

This vulnerability does not occur via an AJAX or REST endpoint that requires a custom plugin nonce. Instead, it is exploited through the standard WordPress post-saving mechanism.

  • Injection Phase: To inject the shortcode via the API or automated requests, the agent will need a standard WordPress REST API or admin-ajax.php nonce for post creation/editing.
  • Extraction: If the agent performs the injection via the browser (Playwright), the browser session handles the _wpnonce automatically.
  • Verification: If there is a need to check for localized scripts that might contain nonces (though not required for this specific XSS), use:
    browser_eval("window.gntt_vars?.nonce") (inferred)

5. Exploitation Strategy

The goal is to inject a stored XSS payload as a Contributor and trigger it as an Administrator.

  1. Step 1: Authenticate as Contributor: Log into the WordPress dashboard using Contributor credentials.
  2. Step 2: Create Malicious Post: Use the http_request tool to create a new post containing the payload.
    • URL: http://[target]/wp-json/wp/v2/posts (or via admin-ajax.php autosave).
    • Method: POST
    • Body:
      {
        "title": "XSS Test",
        "content": "[title-ticker-slide id='\"><script>alert(document.domain)</script>']",
        "status": "publish"
      }
      
    • Note: Contributors' posts usually go to "Pending Review" unless they have publish_posts. However, the XSS will still fire for the Administrator who previews or reviews the post.
  3. Step 3: Trigger XSS: Log in as an Administrator and navigate to the newly created post's URL.
  4. Step 4: Confirm Execution: Use browser_eval to check if a specific global variable (set by the payload) exists or if an alert was triggered.

6. Test Data Setup

  1. Plugin Setup: Ensure gntt-post-title-ticker version 1.0 is installed and activated.
  2. User Setup:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password123
    
  3. Content Setup: (Optional) A page where the shortcode will be displayed.

7. Expected Results

  • When the page is viewed, the HTML source should show the id (or width/height) attribute of the ticker container being closed prematurely by the "> characters.
  • The <script> tag will follow immediately in the DOM.
  • The browser will execute alert(document.domain).

8. Verification Steps

After the exploitation attempt, verify the storage and lack of escaping:

  1. Verify DB Storage:
    wp post list --post_type=post --field=post_content | grep "script"
    
  2. Verify Frontend Output:
    Use http_request (GET) on the post's permalink and check if the response body contains the raw, unescaped payload:
    # Look for the exact unescaped string
    grep 'id=""><script>alert(document.domain)</script>"'
    

9. Alternative Approaches

If the id attribute is partially sanitized, attempt exploitation through other identified vulnerable attributes:

  • Style Injection via header_background:
    [title-ticker-slide header_background='";}</style><script>alert(1)</script>']
  • Width/Height Breakout:
    [title-ticker-fade width='100px" onmouseover="alert(1)" data-x="']
  • Alternative Shortcodes:
    Repeat the process using [title-ticker-fade] or [title-ticker-typing] callbacks, as they share the same vulnerable pattern.
Research Findings
Static analysis — not yet PoC-verified

Summary

The GNTT Post Title Ticker plugin for WordPress is vulnerable to Stored Cross-Site Scripting via shortcode attributes in version 1.0. This occurs because the plugin does not sanitize or escape user-provided attributes like 'id', 'width', and 'height' before rendering them in HTML. Authenticated users with contributor-level access or higher can inject malicious scripts into posts, which execute when the post is viewed by other users.

Vulnerable Code

// gntt-post-title-ticker.php (Inferred)

function gntt_title_ticker_slide($atts) {
    extract(shortcode_atts(array(
        'id' => 'gntt-ticker',
        'width' => '100%',
        'height' => '50px',
        'border' => '1px solid #ccc',
        'header_background' => '#eee',
        'header_text_color' => '#000'
    ), $atts));

    $output = '<div id="' . $id . '" style="width:' . $width . '; height:' . $height . '; border:' . $border . ';">';
    // ... concatenation continues using $header_background and $header_text_color
    return $output;
}

---

function gntt_title_ticker_fade($atts) {
    // Similar logic using unescaped attributes like 'id' and 'width'
    extract(shortcode_atts(array('id' => 'fade-ticker', 'width' => '100%'), $atts));
    return '<div id="' . $id . '" style="width:' . $width . ';">...';
}

---

function gntt_title_ticker_typing($atts) {
    // Similar logic using unescaped attributes like 'id' and 'width'
    extract(shortcode_atts(array('id' => 'typing-ticker', 'width' => '100%'), $atts));
    return '<div id="' . $id . '" style="width:' . $width . ';">...';
}

Security Fix

--- gntt-post-title-ticker.php
+++ gntt-post-title-ticker.php
@@ -10,7 +10,12 @@
-    $output = '<div id="' . $id . '" style="width:' . $width . '; height:' . $height . '; border:' . $border . ';">';
+    $output = '<div id="' . esc_attr($id) . '" style="width:' . esc_attr($width) . '; height:' . esc_attr($height) . '; border:' . esc_attr($border) . ';">';
@@ -25,1 +30,1 @@
-    return '<div id="' . $id . '" style="width:' . $width . ';">...';
+    return '<div id="' . esc_attr($id) . '" style="width:' . esc_attr($width) . ';">...';
@@ -40,1 +45,1 @@
-    return '<div id="' . $id . '" style="width:' . $width . ';">...';
+    return '<div id="' . esc_attr($id) . '" style="width:' . esc_attr($width) . ';">...';

Exploit Outline

The exploit is performed by an authenticated attacker with Contributor-level privileges or higher who has the ability to create or edit posts. 1. The attacker logs into the WordPress dashboard and creates a new post or page. 2. In the post editor, the attacker inserts one of the vulnerable shortcodes (e.g., [title-ticker-slide]) and provides a malicious payload for an attribute that will be rendered within an HTML tag. 3. A payload such as [title-ticker-slide id='"><script>alert(document.domain)</script>'] is used to break out of the HTML attribute context and inject a script tag. 4. The attacker saves the post (or submits it for review). 5. When an administrator or any other user views the post on the frontend or via the 'Preview' function, the unescaped shortcode attribute is rendered directly into the page source, causing the browser to execute the injected JavaScript.

Check if your site is affected.

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