5.34 Freshness and Rollback Protection
An index that verifies is not necessarily current. This section defends against rollback — replaying an older signed index to hide newer packages — and freeze — holding a consumer at a current-but-stale index while its clock runs on.
Every requirement here applies to both the active index and the archive index. An attacker who can replay one can replay the other, and the archive index is the candidate source for every downgrade and pin.
5.34.1 Monotonic index versions #
Each publication of an index MUST set index_version to a value
strictly greater than any previously published value for the same
repository.
A consumer MUST record, per repository, the highest index_version it
has ever observed. On each fetch it MUST reject an index whose
index_version is less than that recorded value, even when the index
is correctly signed by a still-trusted key.
A consumer MUST also record the generated_at of the last index it
trusted, and MUST reject an index whose generated_at is older than the
recorded value.
5.34.2 No progress is a failed fetch #
A fetch returning an index whose index_version and generated_at
both equal the recorded values is a failed refresh, not a successful
one. A consumer MUST NOT advance its "last successful refresh" timestamp
on such a fetch.
5.34.3 The initial floor #
Adding a repository bootstraps the consumer's recorded floor. To defend
against an attacker serving a stale-but-signed index at that moment, a
repository SHOULD distribute a minimum acceptable index_version
alongside its trust anchors, through the same out-of-band channel. A
consumer SHOULD use that minimum as its initial floor, and MUST refuse
the add when the first index fetched falls below it.
A consumer MUST NOT reset a recorded floor as a side effect of any operation other than removing the repository. In particular, re-adding an already-configured repository MUST NOT lower the floor: the operation either applies the recorded floor as a refresh would, or is refused.
5.34.4 Maximum index staleness #
A consumer MUST enforce a maximum staleness window on the index itself,
measured from its generated_at. An index older than 90 days MUST
trigger a refresh attempt before any install operation proceeds.
The 90-day default MAY be tuned by operator configuration; a value greater than 365 days SHOULD generate a warning each time it is exercised.
5.34.5 What these checks buy #
Per-package signing and index signing both still verify under a rollback: the attacker is replaying genuine, correctly signed content. What changes is the set of packages the consumer believes is current. The monotonic version check is what makes that set unable to move backwards, and the no-progress rule is what stops it from being frozen in place.