CVE-2026-24765: RCE in PHPUnit's PHPT test runner
Contents
Overview
A remote code execution vulnerability caused by unsafe deserialization (CWE-502) was found in PHPUnit’s PHPT test runner. The CVSS score is 7.8, rated High.
Affected Versions
| Branch | Affected versions | Fixed version |
|---|---|---|
| PHPUnit 8 | <= 8.5.51 | 8.5.52 |
| PHPUnit 9 | <= 9.6.32 | 9.6.33 |
| PHPUnit 10 | <= 10.5.61 | 10.5.62 |
| PHPUnit 11 | <= 11.5.49 | 11.5.50 |
| PHPUnit 12 | <= 12.5.7 | 12.5.8 |
The impact range is fairly broad.
Vulnerability Details
The cleanupForCoverage() method in the PHPT test runner deserializes code coverage files without validation.
Specifically, it calls @unserialize($buffer) directly. If a malicious .coverage file contains a serialized object with a __wakeup() method, arbitrary code can run during PHPUnit’s cleanup step.
Attack Scenarios
To exploit this issue, an attacker needs to place a malicious file where coverage data is stored. Likely paths include:
- CI/CD pipelines: Submit a pull request containing a malicious
.coveragefile and trigger RCE when tests run - Supply chain attacks: Slip the malicious file in through a compromised dependency
CI/CD environments are especially risky because they often hold secrets and deployment keys.
How to Check Whether You Are Affected
Check the installed PHPUnit version in your project.
composer show phpunit/phpunit
If you use Composer 2.4 or later, composer audit can also check known vulnerabilities.
composer audit
If you wire composer audit into CI, it will help catch similar issues automatically in the future as well.
Mitigation
Updating to a fixed version is the top priority.
composer update phpunit/phpunit
At the infrastructure level, the following are also worth doing:
- Use ephemeral CI/CD runners
- Apply branch protection rules so suspicious files do not get merged easily
- Add tamper detection for test artifacts