Skip to content
Go back

[CVE-2025-50706] From Local File Inclusion to Remote Code Execution in ThinkPHP 5.1

Volerion Research

TL;DR
ThinkPHP 5.1 fails to sanitise the s query parameter that controls route resolution. A crafted path tricks the framework into loading a local PHP file of the attacker’s choice, which runs with the web server’s privileges. Exploit scripts are already public and real-world scans started within hours of disclosure. Patch or block the route entry point immediately.


1. Summary

CVE ID CVE-2025-50706
Affected Product(s) ThinkPHP 5.1.0 through 5.1.x (all minor versions) when URL routing is enabled (default)
Volerion Risk Score 7.9 / 10
Exploit Status Public PoC available
CISA KEV No

Unauthenticated HTTP requests can reach a vulnerable route handler and force the framework to require() any local PHP file that the web-server user can read. Attackers typically create or reuse a file containing a web shell, gaining interactive control without authentication.


2. Context – Why this bug is more than a framework nuance

ThinkPHP is one of the most deployed PHP frameworks in mainland China, powering popular CMS packages such as MetInfo, CMF and FastAdmin. Shared-hosting panels often expose ThinkPHP applications directly to the internet. Because version 5.1 reached End of Life in 2022 many sites still run it without security support, making a fresh critical bug an attractive target for botnets that specialise in PHP exploitation.


3. Technical Details – How the s parameter unravels the sandbox

The vulnerability sits in think\Route::check(). When a request arrives as /index.php?s=<payload> the framework splits the s parameter on slashes and attempts to resolve a controller file. If that resolution fails the code falls back to treating the first path segment as a file relative to the application root and passes the value straight to include.

A minimal exploit chooses a path that walks out of the web root and points at a PHP file the attacker has just uploaded or a legitimate file that can be repurposed, for example PEAR’s pearcmd.php, which accepts command-line arguments from the query string.

GET /index.php?s=../../../Extensions/php/php7.3.4nts/pear/pearcmd.php&+config-create+/&/<?php%20system($_GET['c']);?> HTTP/1.1
Host: victim

Breakdown:

  1. ../../../ escapes the application directory.
  2. The rest of the path lands on pearcmd.php, a helper shipped with many PHP bundles.
  3. Query parameters instruct PEAR to run config-create, which writes the attacker’s PHP code to a writable location.
  4. A second request then loads that file, giving remote code execution.

Because the route handler never verifies that the target file belongs to the application or resides under the web root, any readable PHP file is fair game. The vulnerability therefore combines characteristics of Local File Inclusion (LFI) with arbitrary write primitives provided by helper scripts bundled on the server, forming reliable RCE.

Why allow_url_include is irrelevant

Unlike earlier ThinkPHP 5.0 bugs, this flaw does not rely on php://input or remote URLs. It only needs include and directory traversal which are enabled in every default PHP build, so common hardening guides that disable URL wrappers do not mitigate CVE-2025-50706.


4. Impact – From a single request to full server takeover

Successful exploitation runs the payload as the user that owns the PHP-FPM or Apache worker process. Shared hosting setups often configure that user as the website owner, who can read configuration files containing database credentials. Attackers therefore gain:

SEO spam crews have already added the exploit to automated kits that plant backdoors and malicious redirects. Because ThinkPHP’s file naming conventions are predictable, web application firewalls struggle to distinguish malicious s parameters from legitimate ones.


5. Remediation – What administrators should do now

Upgrade ThinkPHP to the maintained 8.x branch, where the routing engine was rewritten and does not expose the s parameter fallback. If you must stay on 5.1, apply the unofficial patch proposed in pull request thinkphp/thinkphp#2774, which adds realpath() checks before including any file. Alternatively add an early exit in public/index.php:

<?php
if (isset($_GET['s']) && strpos($_GET['s'], '..') !== false) {
    http_response_code(400);
    exit;
}

As a stop-gap, restrict access to index.php?s= endpoints at the web-server level:

location ~* \.php$ {
    if ($arg_s) { return 403; }
}

Do not rely solely on intrusion detection. The exploit payload is fully valid HTTP traffic that changes only one parameter.


6. Timeline

Date (UTC)Milestone
2024-04-24Initial public write-up on xinyisleep blog referencing CNVD-2024-29981
2025-08-05 15:15CVE-2025-50706 published by MITRE
2025-08-05 15:18Volerion completes enrichment and publishes risk score

7. References


About Volerion

Volerion delivers AI-driven enrichment minutes after a CVE goes live. A single call to our REST API returns CVSS 4.0 vectors, exploitability metrics and affected products complete with remediation. Additionally, we offer different scoring profiles, complete with insight into the eight comprehensive categories that make up the final score. Our API is also available in the tradditional NVD API 2.0 format, so integration is as simple as swapping hosts. Spend less time parsing CVEs and more time closing them.

How the Volerion Risk Score Fits With CVSS, EPSS and KEV

At the time of writing:

The Volerion Risk Score of 7.9 places CVE-2025-50706 in our critical band. The score balances the maximum CVSS impact with widespread ThinkPHP deployment and the existence of working exploits even before the CVE ID was assigned.


Share this post on:

Previous Post
[CVE-2025-54571] ModSecurity Content-Type Confusion Exposes Script Source and Enables Stored XSS
Next Post
[CVE-2025-54576] OAuth2-Proxy skip_auth_routes Lets Attackers Walk Straight Past the Login Screen