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:

  1. Route Registration: The upload endpoint is registered via wp_ajax_nopriv_kalrav_upload_file hook (line 967), allowing unauthenticated access.
  2. No Authentication: The wp_ajax_nopriv_ prefix makes the function accessible to unauthenticated users.
  3. No Nonce Verification: The function lacks CSRF protection via nonce verification.
  4. No Capability Checks: No permission validation is performed before allowing file uploads.
  5. Input Processing: User-controlled file data from $_FILES['file'] is directly processed without validation.
  6. 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.
  7. 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();
}