Kalrav AI Agent <= 2.3.3 - Unauthenticated Arbitrary File Upload via kalrav_upload_file AJAX Action
CVE-2025-13374
The WordPress Kalrav AI Agent plugin (version 2.3.3 and prior) contains an arbitrary file upload vulnerability that allows unauthenticated users to upload malicious PHP files to the server, potentially leading to remote code execution.
TL;DR Exploits
A POC CVE-2025-13374.py is provided to demonstrate a remote attacker uploading shell.php and executing remote code:
python3 ./CVE-2025-13374.py http://techcorp.cc
[+] Target: http://techcorp.cc
[+] File uploaded successfully!
[+] Shell URL: http://techcorp.cc/wp-content/plugins/kalrav-ai-agent/uploads/1763247725-shell.php
[+] Command output:
www-data
Technical Description
The vulnerability exists in the kalrav_upload_file() function at the /wp-admin/admin-ajax.php endpoint. The upload functionality lacks proper file validation, nonce verification, and capability checks. This allows unauthenticated users to upload arbitrary files, including PHP files that can be executed on the server.
Attack Path Analysis
Source: User input from $_FILES['file'] (line 978)
Sink: move_uploaded_file($_FILES['file']['tmp_name'], $target_path) (line 982)
The vulnerability occurs because:
- Route Registration: The upload endpoint is registered via
wp_ajax_nopriv_kalrav_upload_filehook (line 967), allowing unauthenticated access. - No Authentication: The
wp_ajax_nopriv_prefix makes the function accessible to unauthenticated users. - No Nonce Verification: The function lacks CSRF protection via nonce verification.
- No Capability Checks: No permission validation is performed before allowing file uploads.
- Input Processing: User-controlled file data from
$_FILES['file']is directly processed without validation. - File Handling: Only basic filename sanitization is applied using
basename():time() . '-' . basename($_FILES['file']['name'])(line 979), which only prevents directory traversal but does not validate file extensions. - File Storage: Files are saved to
wp-content/plugins/kalrav-ai-agent/uploads/.
Vulnerable Code Location
File: kalrav-ai-agent.php
Lines: 969-996
add_action('wp_ajax_kalrav_upload_file', 'kalrav_upload_file');
add_action('wp_ajax_nopriv_kalrav_upload_file', 'kalrav_upload_file');
function kalrav_upload_file()
{
// Path to your plugin uploads folder
$upload_dir = plugin_dir_path(__FILE__) . 'uploads/';
if (!file_exists($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
if (!empty($_FILES['file']['name'])) {
$file_name = time() . '-' . basename($_FILES['file']['name']);
$target_path = $upload_dir . $file_name;
if (move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
wp_send_json_success([
'message' => 'File uploaded successfully!',
'file_path' => $target_path,
'url' => plugins_url('uploads/' . $file_name, __FILE__)
]);
} else {
wp_send_json_error(['message' => 'Failed to move uploaded file.']);
}
} else {
wp_send_json_error(['message' => 'No file uploaded.']);
}
wp_die();
}