CVE-2026-24765 – Unsafe Deserialization Leading to Code Execution in PHPUnit
CVE ID: CVE-2026-24765
Component: PHPUnit – PHPT Code Coverage Handling
Severity: High
CVSS v3.1 Score: 7.8 (High)
Attack Vector: Local
Privileges Required: Low
User Interaction: None
Impact: Remote Code Execution (RCE) during test execution
Exploitability: Practical under common CI/CD and shared runner conditions
Exploit Availability: Proof-of-concept techniques exist and can be recreated for educational and defensive research purposes
Affected Versions
The vulnerability affects PHPUnit versions where unsafe deserialization is performed when handling PHPT code coverage files.
Vulnerable versions include:
- PHPUnit < 12.5.8
- PHPUnit < 11.5.50
- PHPUnit < 10.5.62
- Older maintained branches (9.x, 8.x) if still in use without backported fixes
Official Fix / Upgrade Links
The issue has been resolved in the following official releases. Upgrade to the appropriate version based on the supported branch in use:
- https://github.com/sebastianbergmann/phpunit/releases/tag/12.5.8
- https://github.com/sebastianbergmann/phpunit/releases/tag/11.5.50
Upgrading to these versions fully mitigates the vulnerability.
Technical Description
An unsafe deserialization flaw exists in the way PHPUnit processes PHPT test code coverage data. During execution of PHPT tests with code coverage enabled, a temporary .coverage file is read and deserialized using PHP’s native unserialize() functionality.
In affected versions, this deserialization occurs without strict class restrictions. If a crafted .coverage file is present before test execution, arbitrary PHP objects may be instantiated during deserialization. If those objects implement magic methods such as __wakeup() or __destruct(), attacker-controlled PHP code may be executed automatically.
This behavior results in code execution within the PHPUnit execution context, which commonly includes CI runners, build agents, or developer machines.
Root Cause
- Trust was implicitly placed in the integrity of the
.coveragefile. - PHP object deserialization was performed without limiting allowed classes.
- No validation existed to ensure the coverage file was created by the current test run.
- Pre-existing coverage files were silently accepted and processed.
Exploitation Scenarios
CI/CD Pipeline Exploitation
- Write access to a CI workspace is obtained (via malicious pull request, compromised dependency, shared runner, or misconfigured artifact handling).
- A malicious
.coveragefile containing a serialized PHP object payload is placed in the workspace. - PHPUnit is executed with PHPT tests and coverage enabled.
- The
.coveragefile is deserialized. - Malicious object magic methods execute arbitrary PHP code.
- CI secrets, tokens, or build artifacts are accessed or exfiltrated.
Local Development Abuse
If a developer machine shares writable directories or mounts untrusted volumes, execution may occur during routine test runs, leading to persistence or credential exposure.
Proof-of-Concept (Educational Purpose Only)
A proof-of-concept is trivial to construct and is commonly used in security research demonstrations.
Conceptual payload behavior:
- A PHP class with a
__wakeup()method is serialized. - The method executes a system command (e.g., writing a file or calling
id). - The serialized object is saved as
.coverage. - PHPUnit deserializes the object during PHPT test execution.
MITRE ATT&CK / CWE Mapping
- CWE-502: Deserialization of Untrusted Data
- Tactic: Execution
- Technique: User Execution via Build/Test Process Abuse
Detection Guidance
Key Indicators of Compromise
- Presence of a
.coveragefile before PHPUnit test execution. .coveragefile containing serialized PHP object patterns.- PHPUnit execution errors referencing pre-existing coverage files (post-patch behavior).
- Unexpected child processes or outbound network traffic during test stages.
Log Sources to Monitor
- CI/CD job logs (GitHub Actions, GitLab CI, Jenkins, Azure DevOps)
- Host filesystem audit logs
- EDR process execution logs
- Container runtime logs (for shared runners)
- Artifact repository logs
Detection Patterns
Serialized PHP Object Indicators
Look for these patterns inside .coverage files:
O:<number>:"<ClassName>":
C:<number>:"<ClassName>":
Splunk Detection Rules
Detect Suspicious .coverage File Creation
index=filesystem OR index=os_audit
| search file_name="*.coverage"
| stats count by host, user, file_path, _time
Detect PHPUnit Execution After Coverage File Creation
index=process_logs
| search process_name="php" OR process_name="phpunit"
| join host
[ search index=filesystem file_name="*.coverage" ]
Elastic / SIEM Detection
file.path : "*.coverage" and event.action : "created"
YARA-Style Heuristic
rule PHPUnit_Serialized_Object_In_Coverage {
strings:
$php_obj = /O:\d+:"[A-Za-z0-9_\\]+":\d+:{/
condition:
$php_obj
}
Security Impact
If exploited, the following impacts may occur:
- Full command execution in CI runner context
- Exposure of environment variables and secrets
- Tampering with build artifacts
- Lateral movement within build infrastructure
- Supply-chain compromise
Mitigation and Hardening Guidance
Immediate Actions
- Upgrade PHPUnit to a fixed version.
- Rotate CI secrets if suspicious activity is detected.
- Remove all cached or persistent
.coverageartifacts.
CI/CD Hardening
- Use ephemeral runners for each job.
- Disallow artifacts from untrusted pull requests.
- Block
.coveragefiles in source control. - Disable code coverage in untrusted pipelines.
- Enforce strict workspace cleanup between jobs.
Secure Development Practices
- Avoid PHP deserialization of untrusted data.
- Prefer JSON or structured formats.
- Use
allowed_classes=falsewhere deserialization is unavoidable.
Patch Behavior
In fixed versions:
- PHPUnit refuses to execute PHPT tests if a coverage file already exists.
- Unsafe deserialization paths are hardened.
- The anomalous state becomes visible instead of silently exploitable.
Incident Response Checklist
- Identify and quarantine affected runners.
- Inspect
.coveragefiles for serialized objects. - Review recent CI runs and PR activity.
- Rotate all credentials exposed to runners.
- Enforce patched versions across environments.
Final Takeaway
CVE-2026-24765 represents a high-impact vulnerability in a widely used testing framework. While local in nature, real-world exploitation is highly feasible in CI/CD environments. The vulnerability enables code execution through unsafe deserialization of coverage data and poses a serious supply-chain risk if left unpatched. Immediate upgrade and CI hardening are strongly recommended.
