Two of the most widely used package managers just shipped the same idea. Composer 2.11, released on 29 October, adds a cooldown policy that holds back newly published package versions for a period you choose. On the Node.js side, npm 11.10 added min-release-age earlier this year, joining pnpm, Yarn and Bun, which all shipped equivalent settings in late 2025.
The concept is simple: don't install a package version the moment it's published. Wait, and let someone else find the malware first.
Why Cooldowns Work
According to Packagist, most of the malicious releases it has seen recently came from attackers who briefly took control of a legitimate package, typically through a compromised maintainer account. The pattern is consistent: publish a poisoned version, harvest installs, get flagged, get removed. The whole lifecycle can complete in hours.
That speed is the weakness a cooldown exploits. Automated scanners and registry operators flag most malicious releases quickly, so a version that is only a few hours old is disproportionately likely to be an unflagged attack. If your package manager refuses to install anything published in the last day, you sit outside the window where almost all of the damage happens.
What Composer 2.11 Does
The cooldown lives under config.policy alongside Composer's other dependency policies, and it's off by default:
{
"config": {
"policy": {
"cooldown": {
"period": "1 day"
}
}
}
}
The period accepts strings like "6 hours" or an integer number of seconds, and it can be set globally or via the COMPOSER_POLICY_COOLDOWN_PERIOD environment variable in CI. A few details worth knowing:
- The cooldown applies at resolution time, meaning
composer updateandcomposer require.composer installstill honours your lockfile exactly. composer outdatedandcomposer show --latestreport the newest version the policy allows and flag releases still in their cooldown period.- Dev versions and platform packages are never withheld.
composer update --no-cooldownbypasses the delay for a single run. Your advisory, malware and custom blocking policies stay active.- An
ignorelist exempts packages you always want immediately, such as your own:
"cooldown": {
"period": "1 day",
"ignore": {
"mycompany/*": "We trust the code in our own packages"
}
}
One subtle but important piece: the policy relies on a new published-time field that Packagist.org now reports for every version. The older time field comes from the tag's commit date or the package's own composer.json, and both are controlled by whoever publishes the release. An attacker could simply backdate a malicious version and walk straight past a cooldown built on time. Repositories that don't report published-time fail loudly rather than silently disabling the protection.
The Node.js Ecosystem Got There First
The same control now exists across every major Node.js package manager, though each tool named it differently and picked a different unit of time (yay javascript ecosystem):
- npm 11.10:
min-release-age, in days. An install resolves the newest version that satisfies the age requirement; explicitly requesting a version that's too young errors out. - pnpm:
minimumReleaseAge, in minutes, since 10.16. In pnpm 11 it defaults to1440(one day), making it the only major package manager where the protection is on unless you opt out.minimumReleaseAgeExcludelists exceptions. - Bun 1.3:
minimumReleaseAge, in seconds, inbunfig.toml.
The settings do the same job, but the naming and unit drift means a polyglot team needs to translate one policy into four formats. Worth writing down in your engineering standards rather than leaving to each repository.
The Zero-Day Problem
Our conundrum is that a cooldown applies to every new version, and that includes security fixes.
Composer made this choice deliberately. Security releases get no automatic exemption, because an attacker holding a maintainer's credentials can publish advisories too, or ship a malicious version immediately after a real advisory goes out. Any exemption keyed off advisory data would hand attackers a documented way around the control.
So the delay that protects you from a hijacked composer update also delays the patch for the CVE you read about this morning. Stretch the cooldown to a week and you've built a supply chain defence that guarantees a week of exposure to every known vulnerability in your dependency tree.
Finding the Balance
The risk curves point in opposite directions, which makes the trade-off manageable:
The supply chain benefit concentrates early. Malicious releases are typically flagged and pulled within hours. Packagist suggests even a one-hour cooldown gives automated scanners a chance to act, and recommends a few hours up to a day to catch reports that need a human. The marginal protection from extending past a day shrinks fast.
The zero-day cost compounds linearly. Every extra day of cooldown is a guaranteed extra day between a fix being published and your applications receiving it. For a critical remote code execution in a framework dependency, that's a day of deliberate exposure.
In practice, a cooldown of hours to a day captures most of the supply chain benefit while keeping patch latency acceptable. Longer periods may suit low-change environments, but they need to be paired with a genuine capability to respond to advisories out of band.
Whatever period you choose, three operational details matter more than the number:
- Know your bypass path before you need it. This is where having documented runbooks on security matters pays dividends,
--no-cooldownfor Composer, a targeted install for npm,minimumReleaseAgeExcludefor pnpm. When a critical fix lands, someone on call should be able to pull it deliberately, not discover the mechanism for the first time during an incident. - Watch advisories so bypasses are decisions. A cooldown only costs you the fixes you never hear about. Dependency monitoring, GitHub advisories or your scanner of choice need to tell you when a held-back version is one you actually want now. Additionally, pick your poison for social media to keep tabs on your ecosystem, so that you know when to act fast.
- Keep the other layers. Cooldowns sit alongside lockfiles, integrity verification and restrictions on install scripts, not instead of them. A malicious version that survives undetected for longer than your cooldown still gets in.
The Bigger Picture
Package managers adding release-age gating by default is a signal that dependency hygiene has moved from best practice to baseline expectation. If your update process is still "run the package manager whenever someone remembers," a cooldown is a cheap control to switch on, and a forcing function to think about how you'd respond when speed actually matters.
Supply chain exposure and patch latency are both things we see assessed during penetration tests, because attackers don't distinguish between code you wrote and code you installed. Whichever side of the trade-off you tune towards, make it a deliberate choice with a bypass you've rehearsed.