Oct 2, 2026·6 min read·16 visits
A vulnerability in Composer allows malicious dependencies or manipulated installed.json files to bypass binary path validation. This enables attackers to execute chmod operations or create execution proxies targeting sensitive files outside the package installation directory.
CVE-2026-59944 is a path traversal and link-following vulnerability in Composer, the PHP dependency manager. This flaw allows malicious or compromised packages to bypass previous path-hardening protections and perform arbitrary filesystem operations outside of their designated installation directory, leading to unauthorized permission modifications or execution proxy creations.
Composer is the standard dependency manager for the PHP programming language. It is responsible for downloading packages, resolving dependencies, and preparing the execution environment. This environment often includes generating binary command-line proxies in the vendor/bin directory. This directory is typically included in the host system's PATH variable to allow easy command execution.
To ensure packages can expose command-line utilities, Composer parses the bin configuration array inside each package's composer.json file. This parsing creates file shortcuts or symlinks within vendor/bin. It also attempts to make these binary files executable using the chmod operation. The code paths executing these operations are critical attack surfaces because they manage filesystem writing and permissions.
The vulnerability designated as CVE-2026-59944 represents a bypass of previous directory traversal defenses. A malicious package can exploit improper link resolution or pre-resolved metadata. This allows it to target paths outside the intended installation scope. This technical analysis explores the exact mechanics of the vulnerability, its root causes, and how it was resolved in Composer 2.2.30 and 2.10.3.
To understand the root cause of CVE-2026-59944, one must review the original mitigation for CVE-2026-59946. That mitigation relied on ValidatingArrayLoader::validatePackage() to block any binary path containing double-dot (..) segments. While this blocked literal directory traversal during initial package resolution, it failed to address two critical code execution pathways.
The first pathway is the handling of package files that are physical symbolic links. An attacker can construct a valid package containing a symbolic link at bin/exploit that points outside the package directory. The composer.json file declares the binary path literally as bin/exploit, which contains no directory traversal segments. During initial resolution, the path passes validation. However, during installation, the filesystem extraction writes this physical symbolic link to the disk.
The second pathway involves the restoration or regeneration of package metadata from local sources. When Composer runs a reinstall or executes ensureBinariesPresence(), it reconstructs binaries using vendor/composer/installed.json rather than re-solving the original packages. This localized loading pathway skips the ValidatingArrayLoader checks. If an attacker can write to the installed.json metadata via a shared caching mechanism or a lower-trust build stage, they can insert arbitrary traversal paths directly into the metadata.
Ultimately, both pathways fail because Composer historically performed filesystem operations directly on paths without canonicalizing them first. The program failed to verify that the target of the symbolic link or the path defined in installed.json resolved to a location within the package's install directory. This missing validation allowed the operations to escape the restricted directory boundary.
The vulnerability manifests across two critical components of Composer: FileDownloader.php and BinaryInstaller.php. In vulnerable versions, FileDownloader executed chmod on paths parsed from the package binaries list. The program assumed that the file target was a safe local file. It did not verify whether the file was a physical symbolic link pointing to a system file outside the directory.
The following Mermaid diagram outlines the verification logic that Composer introduces in the patched versions:
In the patch, Composer introduces a physical path containment validation helper isBinPathInsidePackage within BinaryInstaller.php. This helper enforces canonicalization using PHP's native realpath() function:
public static function isBinPathInsidePackage(string $installPath, string $binPath): bool
{
$realBinPath = realpath($binPath);
$realInstallPath = realpath($installPath);
// Fail closed if either path cannot be resolved
if (false === $realBinPath || false === $realInstallPath) {
return false;
}
return strpos($realBinPath, $realInstallPath.DIRECTORY_SEPARATOR) === 0;
}This helper is integrated directly into the downloader and installer loops. In FileDownloader.php, the permission modification is protected as follows:
foreach ($package->getBinaries() as $bin) {
$binPath = $path . '/' . $bin;
if (!file_exists($binPath) || is_executable($binPath)) {
continue;
}
// Validate containment to block directory traversal and symlink manipulation
if (!BinaryInstaller::isBinPathInsidePackage($path, $binPath)) {
continue;
}
Silencer::call('chmod', $binPath, 0777 & ~umask());
}This validation logic ensures that the physical path on the filesystem matches the installation folder context. Any malicious traversal or escaping symlink triggers an validation failure and is safely skipped.
Exploitation of CVE-2026-59944 requires an attacker to inject a malicious package into a target project or compromise an existing dependency. In a standard supply-chain attack scenario, the attacker publishes a package defining a clean path string in composer.json. For instance, 'bin/exploit' is registered. This configuration easily satisfies initial static checks.
The attacker packages bin/exploit as a physical symbolic link pointing to a target system configuration file or shell script. When a developer or CI/CD runner executes composer install, the package archive is downloaded and extracted. The extraction engine recreates the symbolic link on the local filesystem.
During the finalization phase, Composer attempts to make the defined binary executable. It calls chmod on bin/exploit. Because chmod automatically follows symbolic links, the operation changes the target file's permissions. This allows the attacker to alter the permissions of sensitive files, potentially making them world-readable, world-writable, or executable. Additionally, Composer generates an execution proxy script in vendor/bin pointing directly to the target.
The physical impact of this vulnerability depends on the environment and privileges of the executing process. When Composer runs within high-privilege automated environments, such as a CI/CD builder or deployment pipeline, the impact can be severe. The system's binary proxying mechanisms can be manipulated to redirect internal tool chains to unauthorized system files.
The CVSS v3.1 score of 6.1 reflects the necessity of user interaction. An attacker cannot trigger this vulnerability remotely without a user running a Composer command. However, in continuous integration systems where composer install is triggered automatically upon commits or pull requests, this interaction is guaranteed.
By leveraging the file-following nature of the vulnerability, an attacker can modify system file metadata or application configurations. They can alter permissions of restricted resources to extract credentials or execute persistent code. The vulnerability does not directly perform remote code execution, but it serves as a powerful primitive for privilege escalation.
The primary remediation for CVE-2026-59944 is upgrading Composer. System administrators and developers must update their installations immediately. Versions 2.2.30 and 2.10.3 contain the physical path containment check.
If an immediate upgrade is not possible, organizations should implement strict scanning rules on their deployment pipelines. The local environment must not run Composer operations under administrative or root privileges. Running Composer as an unprivileged user limits the impact of arbitrary chmod calls on system files.
Additionally, security teams should implement automated configuration checks. Ensure that the vendor folder is not restored from untrusted cache servers. Developers can audit their codebases for symbolic links by running searching commands to discover links that point outside the project boundaries.
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:N| Attribute | Detail |
|---|---|
| CWE ID | CWE-22, CWE-59 |
| Attack Vector | Local |
| CVSS v3.1 Score | 6.1 (Medium) |
| EPSS Score / Percentile | 0.00322 / 22.99% |
| Impact | Filesystem Permission Modification, Execution Proxying |
| Exploit Status | Proof of Concept |
| CISA KEV Status | Not Listed |
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.