PHP Composer Patches Two Command Injection Flaws in Perforce VCS Driver — Update to 2.9.6 Now
Introduction
Two high-severity command injection vulnerabilities have been disclosed in PHP Composer's Perforce VCS driver. Either flaw lets an attacker execute arbitrary shell commands on the machine running composer install or composer update — no Perforce installation required. Patches shipped in Composer 2.9.6 and 2.2.27 (LTS).
What Happened
Security researchers Koda Reef and saku0512 independently discovered that Composer's Perforce driver builds shell commands by interpolating user-supplied values without proper escaping.
CVE-2026-40176 (CVSS 7.8) targets the Perforce::generateP4Command() method. Connection parameters like port, user, and client are injected directly into command strings. An attacker who plants a malicious composer.json declaring a Perforce VCS repository can embed shell metacharacters in these fields. When a developer clones the project and runs any Composer command, the injected payload executes under that user's context. This attack vector is limited to root composer.json files — dependency packages cannot trigger it.
CVE-2026-40261 (CVSS 8.8) is the more dangerous of the two. It lives in Perforce::syncCodeBase(), where a source reference parameter is appended to a shell command without escaping. Unlike CVE-2026-40176, this one can be exploited through any Composer package repository. A compromised or malicious repository can serve package metadata that declares Perforce as a source type with a weaponized source reference. The payload fires when a developer installs or updates that dependency from source (--prefer-source, which is the default for dev-prefixed versions).
In both cases, the attacker does not need Perforce to be installed on the victim's machine. Composer attempts to execute the constructed command regardless.
The Packagist team confirmed they scanned both Packagist.org and Private Packagist and found no evidence of exploitation prior to disclosure. As a precaution, publication of Perforce source metadata was disabled on Packagist.org on April 10.
Why It Matters
Composer is the backbone of the PHP ecosystem. It runs in CI/CD pipelines, developer workstations, and production deployment scripts across millions of projects. A command injection in Composer's dependency resolution is a supply chain attack vector — a single poisoned package or repository can compromise every machine that pulls it. CVE-2026-40261 is particularly concerning because it reaches through the dependency graph: you don't need to clone a malicious repo, just depend on a package served from one.
Who Is Affected
- Any developer or CI/CD pipeline running Composer versions 2.3 through 2.9.5 (mainline) or 2.0 through 2.2.26 (LTS)
- Projects using
--prefer-sourceor installing dev-prefixed dependencies - Organizations hosting private Composer repositories that serve Perforce-type source metadata
- Any PHP project pulling dependencies from untrusted or community repositories
How to Protect Yourself
Update Composer immediately:
composer self-update
composer --version
# Confirm output shows 2.9.6 or 2.2.27+
If you manage Composer in CI via Docker, pin the new version:
COPY --from=composer:2.9.6 /usr/bin/composer /usr/bin/composer
Audit your lockfile for any dependency declaring perforce as a source type:
grep -r '"type": "perforce"' composer.lock composer.json
Enforce --prefer-dist in CI pipelines to avoid source installs entirely:
composer install --prefer-dist --no-dev --optimize-autoloader
Or set it globally in your composer.json:
{
"config": {
"preferred-install": "dist"
}
}
For Private Packagist Self-Hosted users: upgrade to the latest release and run the verification command referenced in the Packagist security advisory to confirm no metadata on your instance attempts to exploit either CVE.
Review any recently added or unfamiliar dependencies in your composer.lock for unexpected source type declarations.