Composer 2.11 Cooldown: Block Brand-New Package Releases
Table of contents
Composer 2.11 was announced by Packagist on October 29, 2026, and its headline feature is one I have wanted for a long time: a cooldown dependency policy. Turn it on and Composer refuses to pick a package version until it has been public for a period you choose, such as a day or a week. After the wave of malicious npm packages at the end of October, which I wrote about in npm supply chain attacks and Laravel/Vite projects, this is the PHP side of the same defence. Here is how the Composer cooldown works, how I configure it on Laravel and Magento projects, and the traps to know before you enable it.
Why a minimum release age helps
Most supply chain attacks on package registries follow the same pattern: an attacker takes over a maintainer account or a CI token, publishes a poisoned version, and waits for composer update or npm install to pull it into thousands of projects. The malicious version is usually spotted and removed within hours or days, but anyone who updated in that window is already compromised.
A cooldown, also called a minimum release age, simply closes that window. If your projects never install a version younger than a day or a week, most hijacked releases are caught by the community before they ever reach you. It costs nothing in normal times: you get every release, just a little later.
How to configure the cooldown in composer.json
The policy is off by default. You enable it under config.policy.cooldown:
{
"config": {
"policy": {
"cooldown": {
"period": "1 day"
}
}
}
}
The period accepts a string with second, minute, hour, day or week (for example "6 hours" or "7 days"), or a number of seconds. You can also set it in your global Composer config, or with the COMPOSER_POLICY_COOLDOWN_PERIOD environment variable, which is handy for CI.
Your own packages don't need to wait. The ignore option takes package names or wildcards, each with a reason:
"cooldown": {
"period": "3 days",
"ignore": {
"acme/*": "Our own private packages"
}
}
One detail I like: according to Socket's write-up, the age is measured from the time Packagist published the version, not from a date the publisher controls, so a backdated malicious release does not slip through.
Which commands it affects
The cooldown applies when Composer resolves dependencies, which is exactly where new versions enter a project:
composer updateandcomposer require: versions still in cooldown are skipped.composer install: unchanged. It installs exactly what is incomposer.lock, so production deploys behave as before.composer outdatedandshow --latest: show the newest allowed version and flag releases still in cooldown.- Dev branches such as
dev-mainand platform packages are never withheld.
Note that changing the policy config marks the lock file as outdated, so commit the composer.json change and run an update in the same pull request.
What about urgent security releases?
This is the obvious objection: if a framework ships a security fix today, you don't want to wait a week. Composer doesn't guess for you; you decide per package:
composer update --no-cooldown laravel/framework
--no-cooldown works on update, require, remove and create-project, and it only skips the cooldown: advisory and malware blocks still apply. In practice I keep the period short enough (one to three days) that I rarely need it, and I use the flag for the handful of packages where a security release really cannot wait, such as the framework itself or Magento's security patches.
Other changes in Composer 2.11 worth knowing
- Six security fixes, including package names escaping the vendor directory and inline HTTP headers (such as API tokens) being written to the lock file.
- Distrusted eMudhra intermediate certificates are rejected, in line with the CA compromise I covered in the eMudhra post.
- No more silent fallback from dist to source installs. If a zip download fails, Composer stops instead of cloning the repository. Source installs are still available with
--prefer-source. composer audit --directto audit only your direct dependencies, retries on HTTP 429, and faster, lower-memory dependency resolution.
How I'm rolling it out
- Upgrade Composer to 2.11 locally and in CI images (
composer self-update), and check CI does not still pin an older version. - Add a 3-day cooldown to each project's composer.json, with an ignore entry for our own vendor namespace.
- Run
composer outdatedonce to see what the policy is now holding back. - Write the
--no-cooldownprocedure into the team's security runbook, so nobody disables the policy globally in a hurry. - Pair it with the npm equivalent for the front-end build, since a Laravel or Magento project has two dependency trees.
Conclusion
The Composer cooldown is one small block of JSON, it is off by default, and it removes a whole class of supply chain risk for PHP projects. If you maintain Laravel or Magento applications, upgrading to Composer 2.11 and adding a cooldown of a day or a few days is one of the cheapest security improvements you can make this month.