CVE-2026-59948 Overview
CVE-2026-59948 is a path traversal vulnerability [CWE-22] in Composer, the dependency manager for PHP. A maliciously crafted package served from an untrusted repository can cause Composer to write attacker-controlled files outside the vendor directory and outside the project root during install or update operations. The flaw exists because invalid package names are not correctly validated before dependency-resolution results are written or installed. The issue affects Composer versions prior to 2.2.29 and 2.10.2. Packages served from Packagist.org or Private Packagist are not affected.
Critical Impact
An untrusted Composer repository can drop attacker-controlled files anywhere the running user has write access, enabling arbitrary file writes that can escalate to code execution.
Affected Products
- Composer versions prior to 2.2.29 (2.2.x branch)
- Composer versions prior to 2.10.2 (2.x branch)
- PHP projects consuming packages from untrusted third-party Composer repositories
Discovery Timeline
- 2026-07-08 - CVE-2026-59948 published to NVD
- 2026-07-08 - Last updated in NVD database
- Fixes released in Composer 2.2.29 and 2.10.2 via GitHub Security Advisory GHSA-499r-g7pc-vmp9
Technical Details for CVE-2026-59948
Vulnerability Analysis
Composer resolves dependencies and then writes lock data and installs package files based on metadata received from a configured repository. The vulnerable code path in src/Composer/DependencyResolver/LockTransaction.php accepts package names from repository responses without applying the strict validation used elsewhere in the loader pipeline. When a package name contains path traversal sequences such as ../, Composer uses that string to construct file system paths for the lock output and install target. The result is that files are written outside the intended vendor/ directory and outside the project root during normal composer install or composer update runs.
Exploitation requires that the victim adds and trusts a malicious repository entry in composer.json (for example a custom type: composer or type: vcs repository) and then runs an install or update. Packagist.org and Private Packagist perform independent package name validation and are not usable as attack vectors.
Root Cause
The root cause is missing use of the ValidatingArrayLoader package-name validation before lock transaction writes. Package names should be constrained to the documented Composer pattern (vendor/name with a limited character set), but the affected code path treated the repository-supplied name as trusted input when computing install destinations.
Attack Vector
The attack requires user interaction to add a hostile repository and to run Composer, and it executes with local file system privileges of the invoking user. A malicious repository returns a package definition with a crafted name such as vendor/../../../../etc/cron.d/pwn, and Composer resolves and installs it, writing attacker-controlled content to that path.
// Security patch: import ValidatingArrayLoader in LockTransaction
// Source: https://github.com/composer/composer/commit/502c6c4f699802d9cf464728b3e8a95674f919a0
use Composer\Package\AliasPackage;
use Composer\Package\BasePackage;
+use Composer\Package\Loader\ValidatingArrayLoader;
use Composer\Package\Package;
use Composer\Pcre\Preg;
// New SecurityException class introduced by the fix
// Source: https://github.com/composer/composer/commit/502c6c4f699802d9cf464728b3e8a95674f919a0
<?php declare(strict_types=1);
namespace Composer\Exception;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class SecurityException extends \UnexpectedValueException
{
}
Detection Methods for CVE-2026-59948
Indicators of Compromise
- Files created outside the vendor/ directory or outside the project root shortly after a composer install or composer update execution.
- composer.json entries referencing third-party repositories blocks pointing at unverified hosts.
- Package names in composer.lock containing traversal sequences (../, ..\\, absolute paths) or characters outside [a-z0-9_.-]/[a-z0-9_.-].
- Unexpected new or modified files in sensitive paths such as /etc/cron.d/, ~/.ssh/, or web-writable directories on developer or CI hosts.
Detection Strategies
- Audit composer.json and composer.lock files across repositories for non-Packagist repository declarations and validate the referenced hosts.
- Static-scan lock files with a regular expression that rejects any package name not matching ^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.-]?|-{0,2})[a-z0-9]+)*$.
- Enable file integrity monitoring on developer workstations and CI runners for writes outside declared project trees during Composer runs.
- Correlate CI pipeline logs of composer install with file creation events on protected paths.
Monitoring Recommendations
- Log the exit output of Composer in CI and grep for unusual install target paths written to disk.
- Alert on process launches of composer where the parent CI job also generates file writes outside ${CI_PROJECT_DIR}.
- Track the installed Composer version across build agents and flag any host running a version below 2.2.29 or 2.10.2.
How to Mitigate CVE-2026-59948
Immediate Actions Required
- Upgrade Composer to 2.10.2 on the current branch or 2.2.29 on the legacy 2.2 LTS branch immediately on all developer machines, build agents, and container images.
- Inventory all composer.json files and remove or replace untrusted repositories entries; prefer Packagist.org or Private Packagist.
- Rotate credentials and review file system state on any host that ran composer install or composer update against an untrusted repository.
Patch Information
The fix is available in Composer 2.10.2 and Composer 2.2.29. The patch introduces a SecurityException class and routes package names through ValidatingArrayLoader before lock-transaction writes, rejecting names that do not match the Composer naming specification. See the commits 502c6c4 and c50b1ef for the code changes.
Workarounds
- Restrict Composer package sources to Packagist.org or Private Packagist until upgrade is possible.
- Run composer install and composer update inside isolated containers or unprivileged sandboxes so that traversal writes cannot reach sensitive host paths.
- Enforce code review on any pull request that modifies the repositories section of composer.json.
# Upgrade Composer to a patched release
composer self-update 2.10.2
# Legacy 2.2 LTS branch
composer self-update --2.2 2.2.29
# Verify installed version
composer --version
# Audit lock files for suspicious package names
grep -RInE '"name"\s*:\s*"[^"]*(\.\./|\\\\)' ./**/composer.lock
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

