Release-age cooldown¶
mpm can refuse to install or upgrade any package version younger than a chosen release age. This is a supply-chain safeguard: malicious releases (compromised credentials, dependency confusion, account takeover) are typically detected and pulled from registries within days of publication, so a short waiting period keeps the most recent and most likely compromised versions off the system.
Recent examples include the XZ Utils backdoor and recurring vulnerabilities in the VS Code extension marketplace. A delay of even a few days would have given the community time to react.
Quick start¶
The cooldown applies to every install and upgrade mpm performs:
$ mpm --cooldown "7 days" upgrade --all
$ mpm --cooldown "1 week" install some-package
$ mpm --cooldown 12h --allow-no-cooldown upgrade --all # let unsupported managers run too
It accepts a human-readable duration like 7 days, 1 week, 12h, 30m, a bare number of days, or 0 / empty to disable. The value is also settable as the cooldown key in any mpm configuration file (see Configuration for the full schema) or as the MPM_COOLDOWN environment variable.
How it works¶
When cooldown is set, mpm:
Computes a UTC cutoff timestamp equal to
now - cooldown.For each manager that natively enforces a release-age gate (see the support table below), injects the manager’s dedicated environment variable carrying that cutoff into every CLI call. The manager’s own resolver then excludes every version published after the cutoff, including transitive dependencies.
For each manager without a native gate, skips install / upgrade with a warning (fail-closed). Pass
--allow-no-cooldown(or setallow_no_cooldown = truein the config file) to run those managers anyway, without the safeguard.Leaves read-only operations (
outdated,installed,search) untouched: information is never blocked, only mutations are.
The choice to delegate to each manager’s own resolver rather than reimplement the gate inside mpm is deliberate: only the resolver can apply the cutoff to the whole dependency closure (see Limitations below).
Supported managers¶
The table below is the source of truth for which managers mpm can gate today and the state of the upstream effort everywhere else. Statuses:
Enforced:
mpmactively injects a cooldown environment variable on every CLI call. Listed in thecooldown_env_varframework.Shipped upstream: the manager ships a release-age gate but
mpmdoes not (yet) plug into it.Proposed: an open pull request, RFC, or issue is on file upstream.
None: no public proposal found.
N/A: the concept does not apply (distro-curated repositories with their own staging, archived projects, meta-upgraders, …). A structural equivalent is noted when relevant.
|
Status |
Mechanism |
Reference |
|---|---|---|---|
|
None |
— |
— |
|
N/A (archived June 2022) |
— |
|
|
N/A (Debian’s |
— |
|
|
N/A (follows |
— |
— |
|
Proposed (closed as not planned for users; merged for internal bottle resource resolution) |
(internal) |
|
|
Proposed (RFC 3923 merged, nightly implementation) |
|
|
|
Same as |
— |
|
|
None |
— |
— |
|
Proposed |
open PR adds |
|
|
None |
— |
— |
|
None |
— |
— |
|
None (effort focused on |
— |
— |
|
Proposed |
|
|
|
None |
— |
— |
|
None |
— |
— |
|
None |
— |
— |
|
N/A (LVFS staged deployment) |
— |
|
|
Proposed (Bundler PR open) |
|
|
|
None |
— |
— |
|
None |
— |
— |
|
None |
— |
— |
|
None |
— |
— |
|
Enforced |
|
|
|
None |
— |
— |
|
None (Arch AUR helper) |
— |
— |
|
None |
— |
— |
|
None |
— |
— |
|
None (Arch AUR helper) |
— |
— |
|
Enforced (pip ≥ 26.1) |
|
|
|
Enforced (via pip’s env var; needs the underlying pip ≥ 26.1) |
inherits |
|
|
None |
— |
— |
|
None (FreeBSD ports) |
— |
— |
|
None |
— |
— |
|
Proposed |
open feature request |
|
|
None |
— |
— |
|
Inherits from |
— |
— |
|
N/A (risk channels |
|
|
|
None |
— |
— |
|
None |
— |
— |
|
N/A (meta-upgrader; delegates to each underlying manager) |
— |
— |
|
Enforced |
|
|
|
Proposed |
proposed enterprise policy |
|
|
Proposed |
open feature request |
|
|
None |
— |
— |
|
None (project in maintenance mode) |
— |
|
|
Shipped upstream (Berry ≥ 4.10) but unreachable through |
|
|
|
None (Arch AUR helper) |
— |
— |
|
N/A (deprecated alias for |
— |
— |
|
None |
— |
— |
|
None |
— |
— |
Notes¶
brewships an internal release-age gate inside Homebrew’s bottle resource-resolution pipeline (merged inHomebrew/brew#21919) so formulae built from upstream resources get a 24-hour delay automatically. There is no user-facing knob; the issue requesting one was closed as not planned.pipsilently no-ops on releases older than26.1: thePIP_UPLOADED_PRIOR_TOenv variable is unrecognized and ignored. Treat the gate as “best effort” untilmpmlearns to refuse injection on a stale pip (see future directions).yarn-berry: the gate works in Berry≥ 4.10, but Yarn Berry removedyarn global, sompm’syarn-berryhandler only implementssearch. OnboardingnpmMinimalAgeGatewould not change anything reachable throughmpm.apt,snap,fwupdall have structural delays (Debian’s migration windows, Snap risk channels, LVFS staged deployment) rather than per-version age gates. They’re marked N/A because the underlying ecosystem solves the problem in a different shape.The Arch AUR helpers (
pacaur,paru,yay) and most distro front-ends inherit whatever delay the underlying repository / AUR provides; none of them ship a dedicated cooldown setting.
Limitations¶
The transitive-dependency gap¶
mpm’s cooldown is exactly as good as the underlying resolver’s. For managers that install with a real dependency resolver (PyPI, npm, …), the native mechanism applies the cutoff to the whole tree, including transitive dependencies. For managers without a native mechanism, mpm cannot retrofit one without reimplementing the resolver: pinning only the top-level package would leave transitive dependencies fresh, which is precisely the most common attack vector. That is why unsupported managers are fail-closed rather than fail-open.
Coverage limits¶
Distro and system managers (apt, dnf, pacman, brew, …) generally have no per-upstream publish date attached to a package version: their version string is the distro maintainer’s package build, not the upstream release, and the threat model differs (curated repositories with their own staging and review). The concept does not cleanly map. These managers are listed in the support table as N/A.
npm and min-release-age coexistence¶
mpm enforces the cooldown for npm by injecting npm_config_before. On npm 11.x releases predating npm/cli#9368, combining before with a min-release-age setting already present in the user’s .npmrc raises an error. Either upgrade npm or pick one of the two mechanisms.
Read-only consistency¶
The outdated report is not filtered by the cooldown on unsupported managers, so it may list versions that the subsequent upgrade would skip. For supported managers the same environment variable also affects outdated, so the report and the upgrade stay consistent.
Possible future directions¶
Detect the underlying
pipversion at runtime. TodaympminjectsPIP_UPLOADED_PRIOR_TOunconditionally; older pip releases silently ignore it and the gate becomes a no-op, which is the worst failure mode for a security control. Probingpython -m pip --versionand refusing injection below26.1(or bumping the manager’srequirementoutright) closes the false-security window.Route stale pip through
uv pip. For users stuck on pip<26.1,mpmcould borrowuv’s resolver (uv pip install --exclude-newer) whenuvis present, giving sound transitive-correct enforcement without reimplementing one.Onboard mechanisms as they ship upstream. Several managers have active work that would slot into the
cooldown_env_varframework as a one-line addition once released: Composer (#12692), Bundler / RubyGems (#9576), Cargo (stabilization of-Zmin-publish-age, #17009), dnf5 (#2743), Scoop (#6513), winget (#6178), VS Code (#316867).Advisory mode for
outdatedon unsupported managers.mpmcould query each package registry directly (PyPI, RubyGems, crates.io, …) to annotateoutdatedwith a “safe latest” column: purely informational, no install-side enforcement. This avoids the transitive-resolution trap while still being useful. It requires a new HTTP client surface and a state directory for date caching, neither of whichmpmhas today.Block-mode for bundled-artifact managers (
snap,flatpak,vscode,mas). These install self-contained artifacts with no separate transitive resolution at install time, so a “refuse if fresher than the cutoff” check would be sound without a resolver. The bottleneck is per-store API support for per-version publish dates.
Prior art¶
uv
exclude-newer— the model for the Python ecosystem.npm
beforeand its newer companionmin-release-age(shipped innpm11.10).Renovate
minimumReleaseAge— delays dependency PRs by a configurable period.William Woodruff, We should all be using dependency cooldowns.