Repository navigation
fix(federation): share the registration cache fairly between superiors - #620
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The automatic-registration cache held at most 4096 registrations and, once full, cached nothing new rather than evict a valid entry. That kept an attacker from pushing out busy clients, but an intermediate that minted and refreshed 4096 Relying Parties once per cache lifetime kept it full indefinitely, so every other federation client paid a full Trust Chain resolution on every request. Each cached registration is now counted against its immediate superior (the entity that issued its Subordinate Statement, the only one able to mint Relying Parties beside it) and against its branch (the Trust Anchor's own subordinate its chain runs through, which also covers the intermediates an intermediate mints beneath itself): - a superior holds at most 512 entries; its newest registration evicts its own oldest, never anyone else's; - a branch holds at most 2048; past that, and past the overall 4096, expired entries are dropped first and otherwise the new registration isn't cached; - Relying Parties directly under a Trust Anchor can't mint siblings, so they count only against the overall limit. An attacker able to mint Relying Parties can now only ever displace its own. Lookups stay O(1) and an eviction is O(1); the expired-entry sweep runs only when a limit is reached. The cache moves into its own type, and MaxCacheAge's doc and the federation guide describe the policy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
osanderson
force-pushed
the
fix/federation-cache-quota
branch
from
October 9, 2026 12:37
ce66e1e to
e239dd6
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
The automatic-registration cache now limits how much of it any one federation member can occupy:
An intermediate that mints many Relying Parties can now only ever displace its own entries.
Merge after the v0.52.0 release PR (#616). This is a non-breaking fix intended for v0.52.1.
Why
From the v0.52.0 pre-release review. Since #610 the cache was capped at 4096, and once full it cached nothing new rather than evict a still-valid entry. That stopped an attacker pushing busy clients out. But an intermediate that minted and refreshed 4096 Relying Parties once per cache lifetime could keep the cache full indefinitely, so every other federation client paid a full Trust Chain resolution on every request.
Design
Each cached registration records where it sits in its resolved Trust Chain (
ResolvedEntity.Chain):Chain[1], the entity that issued its Subordinate Statement and the only one able to mint Relying Parties beside it;Chain[len-2], the Trust Anchor's own subordinate the chain runs through. This also covers the intermediates an attacker-controlled intermediate mints beneath itself, each of which would otherwise be a new "superior" with its own quota.Policy on insert:
A still-valid entry is never evicted for another superior's registration.
Cost:
The cache moves into its own unexported type (
federation/registration_cache.go).AutomaticRegistrationConfig.MaxCacheAge's doc and the federation guide describe the policy.Verification
chainPosition;export_test.go).registerdropping the chain position;go vet, andgo teston Go 1.27 and 1.26.9;go test -race ./federation/...;GOOS=linux GOARCH=armvet;-racetests, including federated-union.🤖 Generated with Claude Code