CVE-2025-14555

Countdown Timer - Widget Countdown <= 2.7.7 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode

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

Description

The Countdown Timer – Widget Countdown plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the plugin's 'wpdevart_countdown' shortcode in all versions up to, and including, 2.7.7 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<=2.7.7
PublishedJanuary 9, 2026
Last updatedJanuary 10, 2026
Affected pluginwidget-countdown

What Changed in the Fix

Changes introduced in v2.7.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the **Countdown Timer – Widget Countdown** plugin for WordPress. The vulnerability stems from the plugin's failure to sanitize or escape shortcode attributes before rendering them within `<style>` or `<scri…

Show full research plan

This research plan focuses on exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the Countdown Timer – Widget Countdown plugin for WordPress. The vulnerability stems from the plugin's failure to sanitize or escape shortcode attributes before rendering them within <style> or <script> blocks on the frontend.

1. Vulnerability Summary

The wpdevart_countdown shortcode handles several attributes (such as top_ditance, bottom_distance, and font_color) that are used to generate dynamic CSS and JavaScript. Because these attributes are concatenated directly into <style> and <script> tags in includes/front_end.php, a Contributor-level user can provide a payload that breaks out of the intended context (e.g., closing a CSS rule and a </style> tag) to inject arbitrary JavaScript.

2. Attack Vector Analysis

  • Shortcode: [wpdevart_countdown]
  • Vulnerable Attributes: top_ditance (misspelled in code), bottom_distance, font_color.
  • Authentication Level: Authenticated (Contributor or higher). Contributors can create posts and insert shortcodes.
  • Preconditions: The plugin must be active.

3. Code Flow

  1. Entry Point: A user with edit_posts capability (Contributor+) saves a post containing the [wpdevart_countdown] shortcode.
  2. Processing: When the post is viewed, WordPress calls the shortcode handler wpdevart_wpdevart_countdown_shortcode in includes/front_end.php.
  3. Attribute Parsing: The handler uses shortcode_atts() to extract attributes like top_ditance.
  4. Sinks:
    • wpdevart_wpdevart_countdown_shortcode calls $this->wpdevart_countdown_css($curent_value).
    • wpdevart_countdown_css (inferred from line 84) concatenates top_ditance into a string that becomes the content of a <style> block.
    • wpdevart_wpdevart_countdown_shortcode also calls $this->wpdevart_countdown_javascript($curent_value).
  5. Output: The unescaped values are returned in $output_html and rendered on the page.

4. Nonce Acquisition Strategy

This vulnerability is triggered by viewing a post containing a malicious shortcode. No nonce is required to execute the shortcode on the frontend. While the plugin provides an AJAX-based shortcode generator (wpdevart_countdown_window_manager), a Contributor can bypass this UI entirely and manually type the shortcode into the post editor.

5. Exploitation Strategy

The plan is to use the top_ditance attribute to break out of the CSS context and inject a <script> tag.

  • Payload: 15; } </style><script>alert(document.domain)</script><style>
  • Action: Create a post as a Contributor.
  • HTTP Request (Post Creation):
    • Method: POST
    • URL: http://localhost:8080/wp-admin/post.php (or use wp post create via CLI if permitted, but the goal is to simulate the user action).
    • Parameters: post_title=XSS Test&content=[wpdevart_countdown top_ditance="15; } </style><script>alert(document.domain)</script><style>"]&status=publish

6. Test Data Setup

  1. User Creation: Create a user with the contributor role.
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
    
  2. Login: The agent will need to authenticate as attacker.

7. Expected Results

When the post is viewed, the HTML source will contain:

<style>
#main_countedown_1 { margin-top: 15; } </style><script>alert(document.domain)</script><style>px; ... }
</style>

This will cause the browser to execute alert(document.domain).

8. Verification Steps

  1. Manual Check: Navigate to the published post URL using browser_navigate.
  2. DOM Inspection: Use browser_eval to check if a specific "canary" variable exists or if the alert was triggered.
    // Check if the script was injected
    browser_eval("document.body.innerHTML.includes('alert(document.domain)')")
    
  3. Database Check: Verify the shortcode is stored correctly in the database.
    wp db query "SELECT post_content FROM wp_posts WHERE post_title='XSS Test'"
    

9. Alternative Approaches

If top_ditance is sanitized (e.g., cast to int), try the following attributes:

  • font_color: Often used in CSS: font_color="red; } </style><script>alert(1)</script><style>".
  • text_for_day: This attribute is used in wpdevart_wpdevart_countdown_shortcode. Although esc_html is used in the HTML template (line 74), check if it is also passed to wpdevart_countdown_javascript and placed inside a JS variable without escaping.
    • Payload: text_for_day="'; alert(1); //"
  • content: If the countdown expires and the action is not hide, the shortcode content might be rendered.
    • Payload: [wpdevart_countdown end_time="0,0,0" action_end_time="show"]<script>alert(1)</script>[/wpdevart_countdown] (Note: 0,0,0 ensures the timer is expired).

Check if your site is affected.

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