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

CVE-2026-27094: Page Builder Gutenberg Blocks – CoBlocks <= 3.1.16 – Authenticated (Contributor+) Stored Cross-Site Scripting (coblocks)

Plugin coblocks
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 3.1.16
Patched Version 3.1.17
Disclosed January 6, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-27094:
This vulnerability is an authenticated Stored Cross-Site Scripting (XSS) flaw in the Page Builder Gutenberg Blocks – CoBlocks WordPress plugin. The vulnerability affects the Events block component in versions up to and including 3.1.16. Attackers with contributor-level permissions or higher can inject malicious scripts that execute when users view compromised pages.

Root Cause:
The vulnerability stems from insufficient output escaping in the Events block rendering functions. Specifically, the `coblocks_render_single_day_event_item` and `coblocks_render_multi_day_event_item` functions in `/coblocks/src/blocks/events/index.php` fail to properly escape user-controlled data before output. Lines 101-102, 119-120, 138-139, and 156-157 pass unescaped `gmdate()` output directly into HTML strings. Lines 190-191 use unescaped translation strings for button aria-label attributes. Lines 235-245 and 254-255 output unescaped variables including `$date_range`, `$month`, `$year`, `$title`, `$description`, and `$location` directly into HTML.

Exploitation:
An authenticated attacker with contributor privileges creates or edits a post using the CoBlocks Events block. The attacker injects malicious JavaScript payloads into event metadata fields that the plugin stores in post content. When the plugin renders the Events block on the frontend, it outputs the attacker-controlled data without proper escaping. The payload executes in visitors’ browsers when they view the compromised page. The attack requires no special HTTP endpoints, as it exploits the normal WordPress post editing and rendering workflow.

Patch Analysis:
The patch in version 3.1.17 adds proper output escaping throughout the Events block rendering code. The fix applies `esc_html()` to all `gmdate()` function outputs on lines 101, 102, 119, 120, 138, 139, 156, and 157. It adds `esc_attr__()` for translation strings in button aria-label attributes on lines 190 and 191. The patch also applies `esc_html()` to all dynamic variables in the event rendering template: `$date_range`, `$month`, `$year`, `$title`, `$description`, and `$location` on lines 235, 236, 237, 244, 245, and 254. These changes ensure user-controlled data is properly escaped before being output to HTML contexts.

Impact:
Successful exploitation allows attackers to inject arbitrary JavaScript that executes in victims’ browsers. This enables session hijacking, credential theft, content defacement, and redirection to malicious sites. The stored nature means the payload persists and executes for all users viewing the compromised page. With contributor-level access required, this vulnerability primarily affects multi-author WordPress sites where untrusted users have content creation privileges.

Differential between vulnerable and patched code

Code Diff
--- a/coblocks/class-coblocks.php
+++ b/coblocks/class-coblocks.php
@@ -4,7 +4,7 @@
  * Description: CoBlocks is a suite of professional <strong>page building content blocks</strong> for the WordPress Gutenberg block editor. Our blocks are hyper-focused on empowering makers to build beautifully rich pages in WordPress.
  * Author: GoDaddy
  * Author URI: https://www.godaddy.com
- * Version: 3.1.16
+ * Version: 3.1.17
  * Text Domain: coblocks
  * Domain Path: /languages
  * Tested up to: 6.8
@@ -26,7 +26,7 @@
 	exit;
 }

-define( 'COBLOCKS_VERSION', '3.1.16' );
+define( 'COBLOCKS_VERSION', '3.1.17' );
 define( 'COBLOCKS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
 define( 'COBLOCKS_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
 define( 'COBLOCKS_PLUGIN_FILE', __FILE__ );
--- a/coblocks/dist/coblocks-extensions.asset.php
+++ b/coblocks/dist/coblocks-extensions.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-data-controls', 'wp-edit-post', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keycodes', 'wp-plugins', 'wp-primitives', 'wp-rich-text', 'wp-token-list'), 'version' => 'b319aba6626b14679406');
+<?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-data-controls', 'wp-edit-post', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keycodes', 'wp-plugins', 'wp-primitives', 'wp-rich-text', 'wp-token-list'), 'version' => '8edea5818233dc104d0a');
--- a/coblocks/src/blocks/events/index.php
+++ b/coblocks/src/blocks/events/index.php
@@ -99,8 +99,8 @@

 				$event_time_string = sprintf(
 					'<span class="wp-block-coblocks-events__time">%1$s - %2$s</span>',
-					gmdate( 'g:ia', $start_date_string ),
-					gmdate( 'g:ia', $end_date_string )
+					esc_html( gmdate( 'g:ia', $start_date_string ) ),
+					esc_html( gmdate( 'g:ia', $end_date_string ) )
 				);

 				$events_layout .= coblocks_render_single_day_event_item(
@@ -117,8 +117,8 @@

 				$event_time_string = sprintf(
 					'<span class="wp-block-coblocks-events__time">%1$s - %2$s</span>',
-					gmdate( 'g:ia', $start_date_string ),
-					gmdate( 'g:ia', $end_date_string )
+					esc_html( gmdate( 'g:ia', $start_date_string ) ),
+					esc_html( gmdate( 'g:ia', $end_date_string ) )
 				);

 				$events_layout .= coblocks_render_multi_day_event_item(
@@ -136,8 +136,8 @@

 				$event_time_string = sprintf(
 					'<span data-start-time=%1$s data-end-time=%2$s class="wp-block-coblocks-events__time wp-block-coblocks-events__time-formatted"></span>',
-					gmdate( 'c', $start_date_string ),
-					gmdate( 'c', $end_date_string )
+					esc_html( gmdate( 'c', $start_date_string ) ),
+					esc_html( gmdate( 'c', $end_date_string ) )
 				);

 				$events_layout .= coblocks_render_single_day_event_item(
@@ -154,8 +154,8 @@

 				$event_time_string = sprintf(
 					'<span data-start-time=%1$s data-end-time=%2$s class="wp-block-coblocks-events__time wp-block-coblocks-events__time-formatted"></span>',
-					gmdate( 'c', $start_date_string ),
-					gmdate( 'c', $end_date_string )
+					esc_html( gmdate( 'c', $start_date_string ) ),
+					esc_html( gmdate( 'c', $end_date_string ) )
 				);

 				$events_layout .= coblocks_render_multi_day_event_item(
@@ -188,8 +188,8 @@

 		$events_layout .= '</div>';

-		$events_layout .= sprintf( '<button class="wp-coblocks-events-nav-button__prev" id="wp-coblocks-event-swiper-prev" style="visibility: hidden" aria-label="%s"/>', __( 'Previous post', 'coblocks' ) );
-		$events_layout .= sprintf( '<button class="wp-coblocks-events-nav-button__next" id="wp-coblocks-event-swiper-next" style="visibility: hidden" aria-label="%s"/>', __( 'Next post', 'coblocks' ) );
+		$events_layout .= sprintf( '<button class="wp-coblocks-events-nav-button__prev" id="wp-coblocks-event-swiper-prev" style="visibility: hidden" aria-label="%s"/>', esc_attr__( 'Previous post', 'coblocks' ) );
+		$events_layout .= sprintf( '<button class="wp-coblocks-events-nav-button__next" id="wp-coblocks-event-swiper-next" style="visibility: hidden" aria-label="%s"/>', esc_attr__( 'Next post', 'coblocks' ) );

 		$events_layout .= '</div>';

@@ -199,7 +199,7 @@

 	} catch ( Exception $e ) {

-		return '<div class="components-placeholder"><div class="notice notice-error">' . __( 'An error has occurred, check for calendar privileges to make sure it is public or try again later.', 'coblocks' ) . '</div></div>';
+		return '<div class="components-placeholder"><div class="notice notice-error">' . esc_html__( 'An error has occurred, check for calendar privileges to make sure it is public or try again later.', 'coblocks' ) . '</div></div>';

 	}
 }
@@ -234,9 +234,9 @@
 				<span class="wp-block-coblocks-events__year">%3$s</span>
 			</div>
 		</div>',
-		$date_range,
-		$month,
-		$year
+		esc_html( $date_range ),
+		esc_html( $month ),
+		esc_html( $year ),
 	);

 	$event_layout .= sprintf(
@@ -244,8 +244,8 @@
 			<span class="wp-block-coblocks-events__title">%1$s</span>
 			<span class="wp-block-coblocks-events__description">%2$s</span>
 		</div>',
-		$title,
-		$description
+		esc_html( $title ),
+		esc_html( $description )
 	);

 	$event_layout .= sprintf(
@@ -254,7 +254,7 @@
 			<span class="wp-block-coblocks-events__location">%2$s</span>
 		</div>',
 		$time_string,
-		$location
+		esc_html( $location )
 	);

 	return $event_layout;
--- a/coblocks/src/extensions/layout-selector/index.php
+++ b/coblocks/src/extensions/layout-selector/index.php
@@ -62,8 +62,8 @@
  * Localize layout and category definitions for the Layout Selector component.
  */
 function coblocks_localize_layout_selector() {
-	$current_screen   = get_current_screen();
-	$screen_post_type = $current_screen->post_type;
+	$current_screen   = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
+	$screen_post_type = ( $current_screen && isset( $current_screen->post_type ) ) ? $current_screen->post_type : null;

 	$allowed_post_types = array(
 		'page',
@@ -73,7 +73,7 @@
 		'coblocks-editor',
 		'coblocksLayoutSelector',
 		array(
-			'postTypeEnabled' => in_array( $screen_post_type, $allowed_post_types, true ),
+			'postTypeEnabled' => $screen_post_type ? in_array( $screen_post_type, $allowed_post_types, true ) : false,
 			'layouts'         => coblocks_layout_selector_layouts(),
 			'categories'      => coblocks_layout_selector_categories(),
 		)

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.

 

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