When a composer install becomes code execution: CVE-2026-40176 and CVE-2026-40261 in the Composer supply chain

Eine präzise Reihe gleichartiger Kraftpapier-Pakete auf Beton, zwischen zwei Paketen entweicht ein dünner oxbloodfarbener Staubfaden nach oben; daneben Messingstempel und Lupe im kühlen Nordlicht.

Composer is the quiet backbone of every PHP pipeline. That is exactly what makes two vulnerabilities published on 10 April 2026 so unpleasant: a deliberately harmless composer install can lead to arbitrary command execution — even without Perforce installed on the target system.

TL;DR — the 90-second summary

CVE-2026-40176 (CVSS 7.8)

Insufficient escaping in Composer repository metadata — a crafted composer.json leads to code execution in the build user's context

CVE-2026-40261 (CVSS 8.8)

Same class triggerable via any Composer repository including Packagist, no Perforce installation required

Immediate patch

Composer 2.9.6 or 2.2.27 LTS — plus Packagist has disabled publishing of Perforce source metadata

The actual risk

The build user holds SSH keys, registry tokens, cloud credentials — RCE in the build is lateral movement

Four guardrails

Lockfile builds, frozen Composer binary in the CI image, Renovate with cooling-off, read-only Composer mirror

Who is on the hook

every Mittelstand company with a PHP stack — TYPO3, Sylius, Symfony, Laravel are equally exposed

 

What is the problem?

On 10 April 2026 the Composer maintainer team published two vulnerabilities and shipped patches at the same time: CVE-2026-40176 (CVSS 7.8) and CVE-2026-40261 (CVSS 8.8). Both flaws sit on the path where Composer processes repository metadata. A crafted composer.json or a manipulated source reference containing shell meta-characters is insufficiently escaped and passed to a subprocess. Result: arbitrary code execution in the build user's context.

The more severe variant can be triggered via any Composer repository — including Packagist — and does not require a Perforce installation on the target. As an immediate measure, Packagist.org disabled publishing of Perforce source metadata on 10 April.

We were not hit in our pipelines. That is not a feat — it is the result of the same discipline we apply to other tools in our build chain. In this post we frame the incident and describe the structural decisions that make the difference — regardless of whether the next Composer CVE or the next npm wave is coming.

Impact: why a build-RCE is not a build problem

Composer vulnerabilities don't hit the product, they hit the path to it. The actual code in your repository is clean, the app runs, the build would succeed — and in exactly that moment a subprocess on your CI runner executed a foreign command. Three effects make the risk profile uncomfortable.

Builds often run with higher privileges than the running app

SSH keys, container-registry tokens, cloud credentials, deployment tokens — it all sits in the build context. Code execution in the build is therefore almost never just a build problem; it is the step to lateral movement. The same pattern we describe in our CI/CD concentration post.

Composer in CI images is rarely updated

In the pipeline reviews of the past weeks Composer was, in many findings, in a frozen image tag with no automatic update path. A 2.9.4 or 2.8.x in CI stays invisible until an incident makes it visible. Application dependencies get Renovate PRs, the toolchain doesn't.

Composer packages are transitive

Even an organisation that keeps its own composer.json clean depends on the behaviour of tools pre-installed in the CI container and on plugins that load other packages. Exactly that class of plugins contributed in April 2026 — visible in the well-known Intercom Composer plugin incident — to the distribution of the Mini Shai-Hulud wave into the Packagist ecosystem.

Who is affected?

Even a comparatively lean PHP stack usually has a significant number of direct and transitive Composer dependencies. A TYPO3, Sylius or Symfony-based platform is no different here from a larger enterprise stack. Anyone without a clear control loop in CI for which packages are even accepted does not carry a "smaller" risk — just a less visible one.

Three constellations are particularly exposed:

Mitigation and immediate actions — the four guardrails

Quick start in the order in which we currently push pipelines through — each line knocks out a specific class of incidents.

 

composer self-update 2.9.6   # or 2.2.27 (LTS line)
composer diagnose            # check repository list
composer config --global --unset repositories.perforce-*
composer audit               # known vulns against lockfile

 

1. Reproducible installs via composer install against a committed composer.lock

Our builds do not update packages, they install exactly what the lockfile pins. A changed source reference therefore only enters the build via an explicit lockfile commit, not spontaneously in the background. composer update has no place in CI.

2. A defined Composer path locally and in CI

We use a frozen Composer binary in a clearly versioned variant. Composer is not spontaneously updated on the runner via composer self-update; CI images are built, signed, released. The version jump to Composer 2.9.6 or 2.2.27 LTS is therefore a deliberate step, not background activity.

3. Updates via Renovate with cooling-off

New Composer versions are not updated from the shell, but proposed as a pull request and merged after a cooling-off period (typically 72–168 hours). The cooling-off gives the community time to spot a bug or security flaw. The exception remains a known, actively exploited CVE in the running version.

4. Read-only Composer mirror for production builds

Wherever possible, CI runs against an internal mirror that forwards only approved versions. That is effort, but it gives a reliable audit log of which packages ever entered the build context — and filters out packages that have been compromised for an hour of their lifetime on a public registry. Same pattern as the npm mirror we documented after the EVM/DeFi cluster of 6 May.

Detection and verification

Five core questions that bring clarity in half an hour — whether you could be hit today and where the biggest lever sits.

Quick-check snippets we run in the first hour:

 

# Composer binaries across all reachable images
for img in $(docker images --format '{{.Repository}}:{{.Tag}}'); do
  docker run --rm "$img" composer --version 2>/dev/null \
    | grep -i composer
done

# Perforce repositories in the lockfiles
git grep -nE '"type":\s*"perforce"' -- 'composer.lock' '**/composer.lock'

Operator recommendation

What should be operationally in place for which PHP stack right now — in bullet form, because the decisions are usually not between "right" and "wrong", but between "residual risk is accepted" and "residual risk is luck".

Cross-references: the npm EVM cluster post for mirror topologies, the CI/CD concentration post for the structural reasoning, and the AI security audits post for embedding into release discipline.

Conclusion

Most PHP pipelines we see in review have individual pieces. Rarely all of them. Either there is a lockfile, but Composer is pulled in CI via self-update to whatever is the latest binary at the time. Or Renovate dutifully proposes PRs, but without a cooling-off, so a just-compromised version is in the build the next day. Or production servers build differently than CI, and nobody can say with certainty which Composer version is running there after an incident.

The question is not whether Composer 2.9.6 sits in your images. The question is whether your pipeline would even notice the next incident — and whether after noticing you know in the same hour which builds in the days before ran against the compromised version.

A longer write-up with examples of our GitLab CI components, the Renovate configuration and our mirror topology is available (in German) at ole-hartwig.eu.

Frequently asked questions about the Composer CVEs

Why is Composer as a supply-chain vector particularly delicate under NIS-2?+

Because NIS-2 explicitly demands supply-chain security and security in the acquisition and development of systems within its ten risk-management domains. A build pipeline that uncontrollably pulls arbitrary packages from a public registry is exactly where these two domains overlap. Anyone without an audit path over installed packages cannot demonstrate in audit what they actually do.

How long does it take to retrofit these guardrails?+

Lockfile discipline and Composer pinning can be implemented within a few days. Renovate with a maturation window takes a little longer because it must align with your own release logic. A read-only mirror is the larger investment, typically two to three weeks for build-out, sync logic and CI integration. For a clean overall picture we plan with two to four weeks, depending on how grown your pipelines are.

What is the point of an internal Composer mirror when Packagist works fine?+

A read-only mirror inserts a controlled filter between your builds and the public registry. An hour of life for a compromised package on the public side is enough to hit nightly builds. In the mirror nothing happens, because the new package has not been approved. On top, you get an audit log of which packages ever ran in your builds — worth its weight after an incident.

Is upgrading Composer to 2.9.6 enough?+

It is the necessary first step but not sufficient on its own. You don't need to upgrade one Composer installation, you need to upgrade all of them: local dev containers, every CI image, every production server on which Composer runs. If a single worker continues with an old version, the incident has an open path. So check image builds, version pinning and any cron-driven Composer calls.

We do not use Perforce — are we still affected?+

Yes. CVE-2026-40261 (CVSS 8.8) can be triggered through any Composer repository, including Packagist, and does not require a Perforce installation. Composer executes the injected commands even when Perforce is not installed. The other flaw (CVE-2026-40176) is narrower, but the risk profile is set by the more severe one.

Before the next Composer or npm CVE arrives — let's talk about your pipeline.

How disciplined is your PHP pipeline really?

If you run a PHP stack with Composer in CI and on production, the next pipeline review pays off. 30 minutes, no pitch. We walk through with you whether lockfile, Composer binary, Renovate and mirror discipline work in combination — and where the next two or three steps would have the largest lever before the next Composer or npm CVE arrives.

This is the operational routine from DevSecOps as a Service and the Outsourced IT Department — supply-chain hardening as mirror discipline, not as gut feeling.

Book a call directly