CVE-2026-24392

HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce <= 2.14.2 - Authenticated (Author+) 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.14.3
Patched in
47d
Time to patch

Description

The HurryTimer – An Scarcity and Urgency Countdown Timer for WordPress & WooCommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.14.2 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with author-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.14.2
PublishedJanuary 11, 2026
Last updatedFebruary 26, 2026
Affected pluginhurrytimer

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps to verify and exploit **CVE-2026-24392**, a Stored Cross-Site Scripting vulnerability in the HurryTimer plugin. ### 1. Vulnerability Summary * **Vulnerability:** Stored Cross-Site Scripting (XSS) * **Location:** HurryTimer Campaign settings (specifically fi…

Show full research plan

This research plan outlines the steps to verify and exploit CVE-2026-24392, a Stored Cross-Site Scripting vulnerability in the HurryTimer plugin.

1. Vulnerability Summary

  • Vulnerability: Stored Cross-Site Scripting (XSS)
  • Location: HurryTimer Campaign settings (specifically fields like labels, messages, or custom CSS classes).
  • Cause: The plugin fails to sanitize user-supplied input when saving campaign settings and fails to escape the data when rendering the timer on the frontend or in the admin dashboard.
  • Privilege Required: Author or higher.
  • Impact: Execution of arbitrary JavaScript in the context of any user (including administrators) viewing a page where the malicious timer is embedded.

2. Attack Vector Analysis

  • Endpoint: wp-admin/post.php or wp-admin/admin-ajax.php.
  • Target Hook: Typically wp_ajax_ht_save_campaign or the standard save_post hook for the hurrytimer custom post type.
  • Vulnerable Parameter: Likely a sub-field within the campaign's configuration (e.g., headline, label, or cta_text).
  • Preconditions:
    1. The attacker must have an account with the Author role.
    2. The HurryTimer plugin (<= 2.14.2) must be active.

3. Code Flow (Inferred)

  1. Input: An Author user submits a "HurryTimer" campaign via the admin UI.
  2. Processing: The plugin receives the request. In includes/admin/class-campaign-post-type.php (inferred) or a dedicated AJAX handler, the plugin saves the settings using update_post_meta().
  3. Lack of Sanitization: The data is saved directly without being passed through sanitize_text_field() or wp_kses().
  4. Output: When a post containing the [hurrytimer id="XX"] shortcode is viewed, the plugin calls a rendering function (e.g., HT_Campaign::render() in includes/class-campaign.php).
  5. Lack of Escaping: The raw metadata is echoed into the HTML (e.g., echo $settings['headline'];) without using esc_html() or esc_attr().

4. Nonce Acquisition Strategy

HurryTimer uses a modern UI that typically localizes a nonce for AJAX operations.

  1. Identify Trigger: The plugin's scripts are loaded when editing a hurrytimer post type.
  2. Create Setup Page:
    # Create a dummy timer to ensure the UI and scripts load
    wp post create --post_type=hurrytimer --post_status=publish --post_title="Exploit Probe"
    
  3. Navigate and Extract:
    • Navigate to the edit page of the newly created post (e.g., /wp-admin/post.php?post=ID&action=edit).
    • Use browser_eval to extract the nonce from the localized script object. HurryTimer typically uses hurrytimer_admin or hurrytimer_config.
    • Inferred JS Variable: window.hurrytimer_admin?.nonce or window.hurrytimer_config?.save_nonce.

5. Exploitation Strategy

We will attempt to inject the payload through the campaign's "Headline" or "Label" fields.

Step 1: Obtain Nonce and Post ID
Log in as an Author, navigate to the HurryTimer edit screen, and extract the necessary identifiers.

Step 2: Submit Malicious Campaign Update
Submit an HTTP POST request to admin-ajax.php (if AJAX-based) or post.php (if standard form-based).

  • Endpoint: /wp-admin/admin-ajax.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Parameters (Inferred):
    • action: ht_save_campaign (verify via grep)
    • id: [CAMPAIGN_ID]
    • settings: A JSON-encoded string or array containing:
      • headline: <img src=x onerror=alert(document.domain)>
      • label: "> <script>alert(1)</script>
    • _wpnonce: [EXTRACTED_NONCE]

Step 3: Trigger the XSS
Embed the timer in a public post and view it.

  • Shortcode: [hurrytimer id="[CAMPAIGN_ID]"]

6. Test Data Setup

  1. User: Create an Author user.
    wp user create attacker attacker@example.com --role=author --user_pass=password123
    
  2. Campaign: Create a target HurryTimer post.
    wp post create --post_type=hurrytimer --post_title="Vulnerable Timer" --post_status=publish --post_author=$(wp user get attacker --field=ID)
    
  3. Frontend Page: Create a page to display the timer.
    wp post create --post_type=page --post_title="Timer View" --post_content='[hurrytimer id="REPLACE_WITH_ID"]' --post_status=publish
    

7. Expected Results

  • The update_post_meta call succeeds.
  • Upon visiting the "Timer View" page, a JavaScript alert box appears, demonstrating code execution.
  • In the HTML source, the payload appears unescaped: <div class="ht-headline"><img src=x onerror=alert(document.domain)></div>.

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the payload is stored exactly as sent.
    wp post meta get [CAMPAIGN_ID] _hurrytimer_settings
    
  2. Response Check: Use http_request to fetch the frontend page and check for the raw payload.
    # Look for the unescaped script tags
    http_request get "http://localhost:8080/timer-view/" | grep "onerror=alert"
    

9. Alternative Approaches

  • Blind XSS: If the payload doesn't fire on the frontend, check the Admin Campaign List (/wp-admin/edit.php?post_type=hurrytimer). The plugin might display the headline in the list table without escaping.
  • Attribute Injection: If tags are stripped but quotes are not escaped, try breaking out of an attribute: test" onmouseover="alert(1)" style="display:block;width:1000px;height:1000px".
  • Custom CSS Path: Check if the plugin allows "Custom CSS". Inject: </style><script>alert(1)</script>.
Research Findings
Static analysis — not yet PoC-verified

Summary

The HurryTimer plugin is vulnerable to Stored Cross-Site Scripting (XSS) because it fails to sanitize and escape campaign settings, such as headlines and labels, during storage and rendering. Authenticated attackers with Author-level privileges can inject malicious JavaScript into these fields, which executes when any user, including administrators, views the timer on the frontend or backend.

Vulnerable Code

// Inferred from research plan: includes/admin/class-campaign-post-type.php
// Saving campaign settings without sanitization
if (isset($_POST['hurrytimer_settings'])) {
    update_post_meta($post_id, '_hurrytimer_settings', $_POST['hurrytimer_settings']);
}

---

// Inferred from research plan: includes/class-campaign.php
// Rendering campaign settings without escaping
public function render($settings) {
    echo '<div class="ht-headline">' . $settings['headline'] . '</div>';
    echo '<span class="ht-label">' . $settings['label'] . '</span>';
}

Security Fix

--- a/includes/admin/class-campaign-post-type.php
+++ b/includes/admin/class-campaign-post-type.php
@@ -24,7 +24,7 @@
-    update_post_meta($post_id, '_hurrytimer_settings', $_POST['hurrytimer_settings']);
+    update_post_meta($post_id, '_hurrytimer_settings', map_deep($_POST['hurrytimer_settings'], 'sanitize_text_field'));
--- a/includes/class-campaign.php
+++ b/includes/class-campaign.php
@@ -45,7 +45,7 @@
-    echo '<div class="ht-headline">' . $settings['headline'] . '</div>';
+    echo '<div class="ht-headline">' . wp_kses_post($settings['headline']) . '</div>';

Exploit Outline

1. Login to the WordPress admin panel with Author-level credentials. 2. Navigate to the HurryTimer campaign editor (or create a new campaign). 3. Use browser developer tools or a proxy to intercept the save request (typically an AJAX request to `admin-ajax.php` with action `ht_save_campaign` or a POST to `post.php`). 4. Inject a JavaScript payload, such as `<img src=x onerror=alert(document.domain)>`, into fields like `headline`, `label`, or `cta_text` within the `settings` or `hurrytimer_settings` parameter. 5. Save the campaign and obtain its ID. 6. Place the HurryTimer shortcode `[hurrytimer id="[CAMPAIGN_ID]"]` on a public post or page. 7. Visit the public page to trigger the execution of the injected script in the context of the visiting user's session.

Check if your site is affected.

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