CVE-2026-24765: Silent PHPUnit Test Runs Can Turn CI Pipelines into a Code-Execution Trap

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:

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 .coverage file.
  • 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

  1. Write access to a CI workspace is obtained (via malicious pull request, compromised dependency, shared runner, or misconfigured artifact handling).
  2. A malicious .coverage file containing a serialized PHP object payload is placed in the workspace.
  3. PHPUnit is executed with PHPT tests and coverage enabled.
  4. The .coverage file is deserialized.
  5. Malicious object magic methods execute arbitrary PHP code.
  6. 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 .coverage file before PHPUnit test execution.
  • .coverage file 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 .coverage artifacts.

CI/CD Hardening

  • Use ephemeral runners for each job.
  • Disallow artifacts from untrusted pull requests.
  • Block .coverage files 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=false where 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 .coverage files 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.


Aegiron

Backed by 11+ years in cybersecurity and incident response, we decode the latest threats shaping today’s digital battlefield. This blog cuts through the noise with clear insights on vulnerabilities, emerging exploits, and the cyber news defenders can’t afford to miss.