Composer 2.11 の cooldown は「1 日前後」から始める(7 日だと脆弱性ブロックと挟み撃ちで update が止まる)
Composer 2.11 で入った「公開直後の版を一定期間入れない」cooldown を 7 日にすると、既定で有効な既知脆弱性ブロックと組み合わさって、修正版が出た直後に依存解決が不能になる。普段は 1 日前後、7 日待ちたいなら更新 PR 側で待つ二段構えにする。
何が起きるか
- Composer 2.10 から、既知の脆弱性がある版は既定でインストール候補から外される。
- 2.11 の cooldown は、Packagist に出てから設定期間が過ぎていない版を隠す。セキュリティ修正版も例外にしない(乗っ取ったパッケージの攻撃者が自分で「アドバイザリー」を出して素通りさせる抜け道を塞ぐため)。
- その結果、ある依存(報告例では Laravel が必須にしている
symfony/mime、CVE-2026-45070)で修正版が出ると、古い版は脆弱性で拒否、新しい版は cooldown で拒否となり、composer updateが終了コード 2 で失敗する。 - 投稿者の検証では、1 日と 36 時間は成功、40 時間・2 日・7 日・30 日は失敗。境目は修正版の公開からの経過時間(約 39.6 時間)と一致した。7 日設定だと、この状態が数日続く。
- 失敗するのは依存を解決し直す
updateとrequireだけ。composer installはロックファイルどおりに入れるので、7 日設定でも通る。
推奨する運用
- cooldown は数時間〜1 日程度から始める(公式ブログの推奨も「数時間から 1 日」)。設定ドキュメントの例が
7 daysでも、npm のmin-release-age=7や Dependabot の 7 日をそのまま横展開しない。 - 7 日待ちたい場合は、Composer 側は 1 日にしておき、Dependabot などの更新 PR 側で 7 日待つ二段構えにする。
- CI で
composer updateを自動実行しているなら、解決失敗を「cooldown と脆弱性ブロックの衝突」として検知できるようにし、該当パッケージだけ人が判断して上げる手順を決めておく。- 全体を一時的に外す:
composer update --no-cooldown - パッケージ単位で除外する ignore 設定を使う
- 全体を一時的に外す:
- 社内ミラーや Satis など、
published-timeを出せないリポジトリでは cooldown が当てにならないことを把握しておく(次節)。
published-time と time の違い
time の- 従来 Packagist のメタデータにあった
timeは、タグのコミット日時かcomposer.jsonに書かれた値で、公開時刻ではない。投稿者の集計では、2026 年に Packagist へ出た正式版 3,230 件のうち 57% が、公開の瞬間にtimeが 24 時間以上前だった(Laravel から分割配布されるilluminate/*など)。time基準の待機は、悪意がなくても過半数の新版を素通りさせる。 - Packagist は今回から、自分が最初に配信した時刻を
published-timeとして全バージョンに付けている。2.11 の cooldown はこれを使う。 published-timeがないリポジトリでは、Composer は「新旧を判断できない」としてパッケージ名を挙げて停止する。require-published-timeをfalseにすると警告付きでtimeを信じるため、timeを 2020 年に偽装した作りたての版がそのままロックされた(投稿者の検証)。この設定を緩めるのは、偽装の余地を理解したうえで。
注意点
- 数値は投稿者が 2026-10-30 夜(日本時間)に実行した結果で、Packagist の状況で変わる。
- 他のエコシステムの待機期間は Cargo でも「公開直後の版」を待つ(Rust 1.100 の global-min-publish-age) や ソフトウェアサプライチェーン攻撃対策ガイド も参照。