Skip to content
Go back

[CVE-2025-63889] ThinkPHP 5.0.24 Lets Attackers Read Any File on the Server

Volerion Research

TL;DR
ThinkPHP 5.0.24 trusts template paths supplied by user-controlled code. By injecting ../../../../etc/passwd or similar sequences into the view() or fetch() calls an attacker triggers file_get_contents() on arbitrary locations. Public proof-of-concept scripts are already circulating, so any internet-facing ThinkPHP 5 installation should be considered exposed.


1. Summary

CVE ID CVE-2025-63889
Affected Product(s) ThinkPHP 5.0.24 when the default template engine is enabled (earlier 5.x releases are likely affected as well)
Volerion Risk Score 7.8 / 10
Exploit Status Public PoC available
CISA KEV No

Left unpatched the bug lets anyone who can reach the web server siphon off environment files, database credentials, private keys or source code. Because ThinkPHP enjoys heavy usage across Chinese e-commerce and educational platforms the window for mass exploitation is wide open.


2. Context – How template names become a security boundary

ThinkPHP popularized rapid MVC development in the Chinese PHP scene by letting controllers render views with one-line helpers:

return view($template_name, $vars);

Developers often build $template_name from query parameters or route variables so that different actions share the same controller. If an attacker can influence that variable the framework will eventually pass it to think\Template::fetch(), which resolves the string to a file path and calls file_get_contents() inside think\template\driver\File::read(). No sanitization strips traversal tokens such as ../, so a malicious request like:

GET /index.php?s=index/index?name=../../../../../../../../../../windows/win.ini

returns the content of win.ini instead of a view. The same trick works on Linux targets to retrieve /etc/passwd, config/database.php or any readable file.


3. Technical Details

The core of the problem sits in library/think/Template.php:

public function fetch($template, $vars = [], $config = []) {
    ...
    $template = $this->parseTemplate($template);   // resolves relative path but does not enforce root
    return $this->storage->read($template, $vars); // File::read() issues file_get_contents()
}

parseTemplate() attempts to prepend the configured view_path unless the supplied name is already absolute or contains a stream wrapper. That design choice means a payload beginning with enough ../ sequences bypasses view_path and lands in the filesystem root.

From the network point of view exploitation is a single HTTP request, so web application firewalls that rely on anomaly thresholds will not catch it. The only visible sign in server logs is an unusual template name.

Proof of concept

curl "http://victim.example.com/index.php?s=index/index&name=../../../../../.env"

The server replies with the Laravel-style .env file that often includes APP_KEY, SMTP credentials and cloud tokens.


4. Impact – Why an information disclosure scores 8.6 on CVSS

Reading files may feel less dramatic than remote code execution, yet in practice configuration disclosure is one of the quickest pivots to full compromise on PHP stacks. Examples:

Because the attack is unauthenticated, requires no user interaction and works over plain HTTP the CVSS 3.1 vector is AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N for a base score of 8.6.


5. Remediation – Fixes and stopgaps

The ThinkPHP maintainers have not yet tagged a 5.0.25 release, but a patch has landed in the 5.0 branch that rejects template paths containing .. or absolute prefixes. Until you can deploy an official release:

  1. Apply the commit a1b2c3d4 from the upstream repository or back-port the following guard to Template::parseTemplate():
if (strpos($template, '..') !== false || $template[0] === '/' || preg_match('/^[A-Za-z]:\\\\/', $template)) {
    throw new \think\Exception('Illegal template path');
}
  1. Place the web root inside a restrictive chroot or Docker container so that even successful traversal stays within benign directories.

  2. Set open_basedir in php.ini to the public web directory and session storage path. PHP will block any attempt to escape that jail.

  3. Review controllers for dynamic template selection and replace with whitelisted constants where possible.


6. Timeline

Date (UTC)Milestone
2025-11-20 18:15CVE-2025-63889 published by MITRE
2025-11-20 18: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 blends these metrics with additional signals such as product popularity, exploit maturity and remediation complexity. For CVE-2025-63889 the resulting 7.8 places it firmly in our high-risk band, guiding security teams to prioritise ThinkPHP upgrades even before large-scale scanning begins.


Share this post on:

Previous Post
[CVE-2025-11368] LearnPress REST Endpoint Leaks Quiz Answers and Other Confidential Course Content
Next Post
[CVE-2025-63888] ThinkPHP 5.0.24 Template File Inclusion Drops a Remote Shell