Surfaced by Greptile on #2975 (#2975 (comment)), but the pattern is shared by every exporter range endpoint, so it deserves one consistent fix rather than a per-endpoint patch.
Problem
All exporter slot-range loops iterate inclusively with uint64 bounds and no range-size limit:
exporter/validator.go:51 (ValidatorTracesCore) and exporter/validator.go:240 (buildValidatorSchedule)
exporter/committee.go:26 and exporter/committee.go:95
exporter/decided.go:35
Two consequences:
- Unbounded work: a request with a huge
[from, to] window performs one store read per slot (per role), with CPU/memory/response size growing linearly with the range. No validation rejects oversized windows.
- Non-termination: with
to == math.MaxUint64, the inclusive condition s <= request.To is always true and s++ wraps, so the loop never terminates — a single request pins a goroutine forever.
The response-amplification half of the original finding (one note per post-fork slot) was fixed in #2975 by aggregating notes per role; the unbounded-range/overflow half is pre-existing and endpoint-wide, hence this issue.
Suggested fix
Add a shared range validation applied by all exporter query validators (validateValidatorRequest, committee/decideds equivalents):
- reject
to - from > maxSlotRange with a 400 (limit value to be agreed — needs a product/API-contract decision, e.g. a few epochs' worth of slots),
- which also removes the
MaxUint64 wrap case, since any to that survives validation leaves the loop finite.
Document the limit in the OpenAPI descriptions of the affected endpoints.
Surfaced by Greptile on #2975 (#2975 (comment)), but the pattern is shared by every exporter range endpoint, so it deserves one consistent fix rather than a per-endpoint patch.
Problem
All exporter slot-range loops iterate inclusively with
uint64bounds and no range-size limit:exporter/validator.go:51(ValidatorTracesCore) andexporter/validator.go:240(buildValidatorSchedule)exporter/committee.go:26andexporter/committee.go:95exporter/decided.go:35Two consequences:
[from, to]window performs one store read per slot (per role), with CPU/memory/response size growing linearly with the range. No validation rejects oversized windows.to == math.MaxUint64, the inclusive conditions <= request.Tois always true ands++wraps, so the loop never terminates — a single request pins a goroutine forever.The response-amplification half of the original finding (one note per post-fork slot) was fixed in #2975 by aggregating notes per role; the unbounded-range/overflow half is pre-existing and endpoint-wide, hence this issue.
Suggested fix
Add a shared range validation applied by all exporter query validators (
validateValidatorRequest, committee/decideds equivalents):to - from > maxSlotRangewith a 400 (limit value to be agreed — needs a product/API-contract decision, e.g. a few epochs' worth of slots),MaxUint64wrap case, since anytothat survives validation leaves the loop finite.Document the limit in the OpenAPI descriptions of the affected endpoints.