CVE-2025-12057: the WordPress audio plugin that hands attackers your whole server
An unauthenticated arbitrary-upload → RCE in WavePlayer < 3.8.0 (CVSS 9.8) — mass-exploited in WP-SHELLSTORM despite a low EPSS and no KEV listing

A music widget is not the first place most teams look for a critical flaw. But WavePlayer — a popular commercial WordPress/WooCommerce audio player — shipped an unauthenticated arbitrary file upload in every version before 3.8.0, and the shortest path from that bug to a live webshell is about two HTTP requests. No login, no user interaction, full server compromise. Below: exactly how the chain works, why the usual "is it urgent?" signals under-called it, and what to do today.
Scores as of 2026-07-14live record →
What the flaw actually is
WavePlayer exposes an AJAX action called create_local_copy through its own query-string dispatcher (?wvpl-ajax=create_local_copy). Two mistakes stack on top of each other. First, the action performs no authorization check — an anonymous request reaches it. Second, it takes a url parameter naming a remote file, fetches it, and copies it locally with no validation of type, extension, or path. That's the classic CWE-434 (unrestricted file upload) shape, and here it lands in a web-served directory, so the write becomes execution (WPScan, NVD).
The exploitation chain
Put together, the attack is short and mechanical — which is exactly why mass scanners love it. Grab a nonce, POST the create_local_copy action with a url pointing at an attacker-hosted PHP payload, and the plugin writes that payload to a predictable path under wp-content/uploads/peaks/external/. Request the dropped file directly and the PHP runs. The flow below traces the whole thing, with the two chokepoints where defenders can break it.
CVE-2025-12057 exploitation chain
- Internet-facing WP with WavePlayer < 3.8.0 — An anonymous attacker or FOFA-style mass scanner finds a reachable site with the plugin active on a vulnerable build.
- Scrape the public ajax nonce — WavePlayer prints `ajax_nonce` into any public page's HTML — the attacker regexes it out. Not an auth barrier.
- create_local_copy reachable unauthenticated? — The AJAX action has no capability check. If reachable, the anonymous POST proceeds to the file-copy sink.
- POST create_local_copy with a remote PHP url — Body carries `nonce` + `url=http(s)://attacker-host/payload`. No file-type/path validation (CWE-434).
- PHP written to wp-content/uploads/peaks/external/ — Payload lands in a predictable, web-served, PHP-executable directory; the response even discloses the path.
- Request the webshell → unauthenticated RCE — Directly requesting the dropped .php executes it — full pre-auth remote code execution in ~two requests.
- Persistence & access resale — Seen in WP-SHELLSTORM: webshells, a VShell backdoor, access packaged and resold. Patching the plugin does NOT evict this.
- Prevent: update to 3.8.0 / disable plugin — Update to WavePlayer >= 3.8.0, or deactivate it until you can. The only real fix.
- Detect: WAF block + FIM on uploads/*.php — Block unauth POSTs carrying create_local_copy + off-site url; alert on any new .php under wp-content/uploads/; disable PHP execution there.
Am I affected?
WavePlayer is a paid CodeCanyon plugin, so it won't surface in wordpress.org-based scanners the way free plugins do — check the plugin folder and admin screen directly. Anything below 3.8.0 is vulnerable; the fix is 3.8.0.
| WavePlayer version | Status |
|---|---|
| ≤ 3.7.0 (all builds before 3.8.0) | Vulnerable — unauthenticated arbitrary upload → RCE |
| 3.8.0 and later | Fixed — update here |
Exploited in the wild — the WP-SHELLSTORM campaign
This is not a theoretical bug. Researchers who found an exposed attacker server documented a mass-compromise operation dubbed WP-SHELLSTORM, and WavePlayer's flaw is named among the ~27 plugin CVEs it weaponized to drop webshells. Australia's national cyber agency (ACSC) later warned about the same global campaign and listed this CVE among the exploited plugins (SOCRadar, The Hacker News, Cyber Daily).
Timeline
Disclosure → exploitation
- Public PoCA weaponized proof-of-concept appears publicly, lowering the bar to mass exploitation.
- Not on CISA KEVStill absent from KEV despite documented mass exploitation.
The part that should worry triage teams
Two signals a lot of teams lean on both said skip it. EPSS sat around 0.4% (~34th percentile) and the flaw is not on CISA KEV — while attackers were mass-scanning for it. That's not a knock on those signals so much as a reminder of what they measure: EPSS is trained on observed telemetry, so obscure commercial-plugin bugs stay low until enough exploitation data feeds back in, and CISA rarely adds individual WordPress-plugin CVEs to KEV even during active campaigns (Wordfence).
Detection & hunting
Hunt two things: the exploit request and the file it drops. In web access logs, look for unauthenticated POSTs to the create_local_copy action carrying a url parameter that points at an external host. On disk, treat any new .php under wp-content/uploads/ as suspicious — the PoC writes to wp-content/uploads/peaks/external/. Note there is currently no public Nuclei template for this CVE, so a template-only scan will give you a false all-clear; fall back to plugin-inventory and asset-path fingerprinting.
- Exposure: confirm whether WavePlayer is installed and its version (
wp plugin get waveplayeror the plugin header/readme); < 3.8.0 is vulnerable. - Request hunt: access-log POSTs to
create_local_copywithurl=http(s)://…off-site. - Drop hunt / FIM: new
.phpfiles underwp-content/uploads/**— especially…/peaks/external/. - Assume-compromise: if the site was reachable on a vulnerable build, check for webshells, added admin users, and modified core/plugin files before closing the ticket.
# Virtual patch + hardening while you roll out 3.8.0
# 1) Block the unauth exploit request at the WAF/proxy (sketch):
# deny POST where arg wvpl-ajax == create_local_copy AND arg url matches ^https?://
# 2) Neutralise the RCE even if a file is written — no PHP under uploads:
location ~* /wp-content/uploads/.*\.php$ { deny all; }What to do now
- Update WavePlayer to 3.8.0 or later via the vendor's licensed-update channel, and confirm the build actually moved.
- Can't patch this hour? Virtual-patch it: block the
create_local_copyaction for unauthenticated requests and deny.phpexecution underwp-content/uploads/. Deactivating the plugin is the safest stopgap. - If it was exposed: run a compromise assessment — hunt webshells, rotate WordPress salts and admin credentials, and review for persistence. A patch removes the bug, not an attacker who already dropped a shell.
FAQ
Is CVE-2025-12057 being exploited?
Do I need to be logged in to exploit it?
create_local_copy action has no authorization check, and the WordPress nonce it uses is printed on public pages, so it behaves as a fully unauthenticated flaw.How do I fix it?
wp-content/uploads/, or deactivate the plugin. Check a live score and details on the CVE page.I patched — am I safe?
.php files under uploads and rotate secrets before you consider it resolved.Sources
- WPScan advisory — WavePlayer unauthenticated arbitrary file upload
- NVD — CVE-2025-12057
- GitHub Advisory GHSA-5h9q-jf3c-852w
- Wordfence Intelligence — WavePlayer ≤ 3.7.0 unauthenticated arbitrary file upload
- SOCRadar — WP-SHELLSTORM exposes 1.4M WordPress sites
- The Hacker News — exposed hacker server reveals WordPress campaign
- eSecurity Planet — WP-SHELLSTORM backdoored thousands of WordPress sites
- Cyber Daily — ACSC warns of large-scale CMS exploitation
- BleepingComputer — Australia warns of global CMS campaign