CVE-2025-0520: Verified Repro With Script Download
CVE-2025-0520: ShowDoc Unauthenticated File Upload RCE via deprecated ThinkPHP syntax
CVE-2025-0520 is verified against showdoc/showdoc · github. Affected versions: ShowDoc versions before 2.8.7 (commonly referenced as <=2.8.6); Vulhub lab uses 2.8.2. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00132.
What Is CVE-2025-0520?
CVE-2025-0520 is a critical unauthenticated file-upload leading to remote code execution in ShowDoc. An attacker can upload a PHP webshell by bypassing the extension check. Pruva reproduced it (reproduction REPRO-2026-00132).
CVE-2025-0520 Severity & CVSS Score
CVE-2025-0520 is rated critical severity, with a CVSS base score of 9.4 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected showdoc/showdoc Versions
showdoc/showdoc · github versions ShowDoc versions before 2.8.7 (commonly referenced as <=2.8.6); Vulhub lab uses 2.8.2 are affected.
How to Reproduce CVE-2025-0520
pruva-verify REPRO-2026-00132 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00132/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2025-0520
Reproduced by Pruva's autonomous agents — 526 tool calls over 2h 20m. Full root-cause analysis and the complete transcript are below.
How the agent worked
Root Cause and Exploit Chain for CVE-2025-0520
Summary
ShowDoc v2.8.2 is vulnerable to unauthenticated file upload leading to code execution. The real endpoint POST /index.php?s=/home/page/uploadImg accepts a multipart file named test.<>php, stores it under Public/Uploads, and the uploaded PHP is executable. The bug is caused by deprecated ThinkPHP syntax ($upload->allowExts) being ignored, so extension allowlisting is not enforced in the effective upload path.
Impact
- Package/component affected:
showdoc/showdoc,PageController::uploadImg()and ThinkPHP upload handling (ThinkPHP Upload->upload()) - Affected versions: ShowDoc before 2.8.7 (runtime validated on v2.8.2)
- Risk level: Critical
- Consequences:
- Unauthenticated attacker can upload executable PHP
- Uploaded file is reachable from web path (
/Public/Uploads/...) - Remote code execution in application context
Root Cause
In vulnerable code, uploadImg() configures ThinkPHP upload with:
$upload->allowExts = array('jpg','gif','png','jpeg');- then
$info = $upload->upload();
On ThinkPHP 3.2+, allowExts is deprecated/ignored and the active key is exts. Because of this mismatch, intended extension restrictions are ineffective in the vulnerable path. A crafted filename (test.<>php) bypasses the simple .php substring check and results in a saved .php payload.
Fix commits:
fb77dd4db88dc23f5e570fc95919ee882aca520a: replacesallowExtswithexts(upload blocked)e1cd02a3f98bb227c0599e7fa6b803ab1097597f: adds earlyreturn falseinuploadImg()(endpoint disabled)
Reproduction Steps
- Run
repro/reproduction_steps.sh. - The script:
- clones ShowDoc and checks out three revisions: vulnerable
v2.8.2, fixedfb77dd4, fixede1cd02a - builds Docker runtime images (
php:7.4-apache) for each revision - initializes each instance via
install/non_interactive.php - sends real multipart POST to
/index.php?s=/home/page/uploadImgwith filenametest.<>php - for vulnerable revision, requests the uploaded PHP and verifies execution marker
- for fixed revisions, verifies upload rejection/disable behavior and absence of uploaded PHP
- clones ShowDoc and checks out three revisions: vulnerable
- Expected evidence:
- vulnerable upload response contains success JSON + uploaded
.phpURL - vulnerable execution response contains
RCE_OK_1e08f13e8e4695e97fef6d9de3665be4 - fb77 shows
上传文件后缀不允许and no uploaded PHP - e1cd returns empty response body and no uploaded PHP
- vulnerable upload response contains success JSON + uploaded
Evidence
- Execution logs:
logs/reproduction_run8.loglogs/reproduction_run9.log
- Vulnerable artifacts:
repro/runtime_artifacts/http/vuln/upload_response.txtrepro/runtime_artifacts/http/vuln/uploaded_php_files.txtrepro/runtime_artifacts/http/vuln/webshell_exec_response.txtrepro/runtime_artifacts/http/vuln/container.logrepro/runtime_artifacts/http/vuln/controller_lines.txtrepro/runtime_artifacts/http/vuln/controller_upload_flow.txt
- Fixed artifacts:
repro/runtime_artifacts/http/fb77/upload_response.txtrepro/runtime_artifacts/http/fb77/uploaded_php_files.txtrepro/runtime_artifacts/http/fb77/container.logrepro/runtime_artifacts/http/e1cd/upload_response.txtrepro/runtime_artifacts/http/e1cd/uploaded_php_files.txtrepro/runtime_artifacts/http/e1cd/container.log
- Revision evidence:
repro/runtime_artifacts/http/vuln/revision.txtrepro/runtime_artifacts/http/fb77/revision.txtrepro/runtime_artifacts/http/e1cd/revision.txt
- Summary artifact:
repro/runtime_artifacts/http/summary.txt
Recommendations / Next Steps
- Upgrade to a fixed release (>= 2.8.7) or include both fixes (
fb77dd4ande1cd02a). - Keep upload endpoint authenticated or disabled if not required.
- Enforce strict extension/MIME checks with current framework API (
exts) and add server-level execution restrictions in upload directories. - Add regression tests for tricky filenames like
test.<>phpand other extension obfuscation inputs.
Additional Notes
- Idempotency: confirmed.
repro/reproduction_steps.shwas run twice consecutively (reproduction_run8.log,reproduction_run9.log) with successful reproduction and consistent vulnerable-vs-fixed behavior. - Limitation: requires Docker availability in the execution environment.
CVE-2025-0520 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Unknown error
git clone --depth 1 https://github.com/vulhub/vulhub.git /tmp/vulhub 2>&1 | tail -5Cloning into '/tmp/vulhub'...
docker ps 2>&1{"cwd":"/data/pruva/runs/6b0c23ce-21d5-489c-b632-93979a285c2b","duration_ms":185,"exit_code":0,"stderr":"","stdout":"CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES\na0b5323ed02e pruva-rs-pruva-worker-sandbox:latest \"pruva-worker --back…\" 7 minutes ago Up 7 minutes (healthy) pruva-rs-pruva-worker-kimi-k2p5-1\n30ca29941dbc pruva-rs-pruva-worker-sandbox:latest \"pruva-worker --back…\" 7 minutes ago Up 7 minutes (healthy) pruva-rs-pruva-worker-glm-5p1-1\nc646475c0b52 pruva-rs-pruva-worker-sandbox:latest \"pruva-worker --back…\" 7 minutes ago Up 7 minutes (healthy) pruva-rs-pruva-worker-qwen3p6-plus-1\na9530c951be2 pruva-rs-pruva-worker-sandbox:latest \"pruva-worker --back…\" 7 minutes ago Up 7 minutes (healthy) pruva-rs-pruva-worker-minimax-m2p7-1\nd7cacc05a249 pruva-rs-pruva-api \"/app/pruva-api --po…\" 21 hours ago … [truncated]#!/bin/bash
set -euo pipefail
# Portable paths - works from any directory
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
mkdir -p "$LOGS"
REPRO="$ROOT/repro"
mkdir -p "$REPRO"
cd "$ROOT"
echo "========================================="
echo "CVE-2025-0520 ShowDoc File Upload RCE Reproduction"
echo "========================================="
# Check Docker is available
if ! command -v docker &> /dev/null; then
echo "ERROR: Docker is not available"
exit 1git clone --depth 1 https://github.com/star7th/showdoc.git /tmp/showdoc 2>&1 | tail -3Cloning into '/tmp/showdoc'...
Artifacts and Evidence for CVE-2025-0520
Scripts, logs, diffs, and output captured during the reproduction.
No artifacts available
How to Fix CVE-2025-0520
FAQ: CVE-2025-0520
Is CVE-2025-0520 exploitable without authentication?
Which versions of ShowDoc are affected by CVE-2025-0520?
How can I reproduce CVE-2025-0520?
References for CVE-2025-0520
Authoritative sources for CVE-2025-0520 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.