Podlove Podcast Publisher <= 4.2.6 - Unauthenticated Arbitrary File Upload RCE (CVE-2025-10147)
by GHOSTPEL-SEC (PoC); Arkadiusz Hydzik (original discovery) · 2026-07-06
- Severity
- Critical
- CVE
- CVE-2025-10147
- Category
- web
- Affected product
- Podlove Podcast Publisher (WordPress plugin)
- Affected versions
- <= 4.2.6
- Disclosed
- 2026-07-06
- Patch status
- unpatched
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-06 |
| Last Updated | 2026-07-06 |
| Author / Researcher | GHOSTPEL-SEC (PoC); Arkadiusz Hydzik (original discovery) |
| CVE / Advisory | CVE-2025-10147 |
| Category | web |
| Severity | Critical |
| CVSS Score | 9.8 (per NVD) |
| Status | Weaponized |
| Tags | wordpress, podlove, podcast-publisher, unauthenticated-file-upload, rce, cwe-434, python |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Podlove Podcast Publisher (WordPress plugin) |
| Versions Affected | <= 4.2.6 |
| Language / Platform | Python 3 (exploit); PHP / WordPress (target) |
| Authentication Required | No |
| Network Access Required | Yes |
Summary
The Podlove Podcast Publisher plugin for WordPress is vulnerable to arbitrary file upload due to missing file type validation in the move_as_original_file function, present in all versions up to and including 4.2.6. The plugin’s image-caching route accepts an externally hosted URL as a parameter and fetches/caches it locally under wp-content/cache/podlove/ without verifying that the fetched content is actually an image, so a remote PHP file disguised behind an arbitrary URL/extension gets written to a web-accessible cache path. The included PoC (ghostpelsec.py) hex-encodes an attacker-controlled “shell” URL, requests it through Podlove’s /podlove/image/<hex>/100/100/0/<filename> endpoint to trigger the fetch-and-cache, then brute-forces the resulting MD5-hash-derived cache subdirectory/filename to locate and confirm the uploaded PHP shell, finally testing command execution via a ?cmd= parameter.
Vulnerability Details
Root Cause
Podlove’s image-proxy/cache handler builds a local cache file from a remote URL supplied via the request path without validating that the fetched resource is actually image content or restricting the file extension of the cached copy. The move_as_original_file function persists the downloaded content into the plugin’s public cache directory using a filename/extension effectively controlled by the request, allowing a .php (or PHP-executable) file to be written and later requested directly by the web server.
Attack Vector
- Attacker hosts a PHP web shell at an externally reachable URL (e.g. an R2/S3 bucket or attacker web server), using a filename such as
shell.gif.php. - Attacker hex-encodes that shell URL and requests it via the target’s Podlove image route:
GET /podlove/image/<hex-encoded-shell-url>/100/100/0/<filename>— this causes the plugin to fetch the remote file and cache a local copy underwp-content/cache/podlove/<md5-derived-subdir>/. - The attacker computes the expected cache subdirectory as
md5(shell_url + filename)and probes a set of likely cached filenames (<filename>_original.php,original.php, etc.) under that path. - Once the cached PHP file is located and confirmed (the PoC checks for a hardcoded marker string in the response), the attacker requests it directly with a
?cmd=query parameter to achieve remote code execution.
Impact
Unauthenticated remote code execution on the WordPress host running the vulnerable plugin, since the attacker fully controls the content and can execute arbitrary PHP once it lands in a web-accessible cache directory.
Environment / Lab Setup
Target: WordPress site with Podlove Podcast Publisher <= 4.2.6 installed and activated
Attacker: Python 3, `pip install requests`
Shell: A PHP web shell hosted at an attacker-controlled, publicly reachable URL
(the original PoC used a Cloudflare R2 bucket URL as the "shell-url" input)
Proof of Concept
PoC Script
See
ghostpelsec.pyin this folder.
| |
Detection & Indicators of Compromise
Signs of compromise:
- PHP files present in
wp-content/cache/podlove/cache subdirectories (this cache should only ever contain image files) - Requests to cached files with a
?cmd=query parameter returning command output - Outbound HTTP fetches from the server to attacker-controlled domains immediately preceding new files appearing in the Podlove cache
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade Podlove Podcast Publisher to a version that validates fetched content as a genuine image and restricts cached file extensions before writing to wp-content/cache/podlove/ — see the vendor’s changelog for the version following 4.2.6 |
| Interim mitigation | Block or disable the Podlove image-cache route at the web server/WAF level, restrict outbound requests from the WordPress host, and audit wp-content/cache/podlove/ for non-image files |
References
Notes
Mirrored from https://github.com/ghostpel-sec/CVE-2025-10147 on 2026-07-06. The PoC is a fully functional Python exploit; it verifies the attacker-hosted shell for a hardcoded “Ghostpel-SEC” marker string before and after upload, so it will not work against an arbitrary shell without that marker — this is exploit-author branding baked into the verification logic, not a functional requirement of the underlying vulnerability itself.
| |