In RequireAPIKey, a rate-limiter bucket is allocated in sync.Map before the DB lookup — one entry per unique key hash. An attacker flooding with many distinct fake bearer tokens creates one entry per hash, and entries live until the 5-minute sweep. Each *rate.Limiter is ~100 bytes, so the risk is low but real.
A lightweight mitigation is a per-IP cap as a first gate in RequireAPIKey, before any key parsing or bucket allocation:
if !iprl.Allow(ClientIP(r)) {
w.Header().Set("Retry-After", strconv.Itoa(iprl.RetryAfterSeconds()))
jsonError(w, "rate limit exceeded", http.StatusTooManyRequests)
return
}
This would require passing a second RateLimiter (IP-based) into RequireAPIKey alongside the existing per-key one.
In
RequireAPIKey, a rate-limiter bucket is allocated insync.Mapbefore the DB lookup — one entry per unique key hash. An attacker flooding with many distinct fake bearer tokens creates one entry per hash, and entries live until the 5-minute sweep. Each*rate.Limiteris ~100 bytes, so the risk is low but real.A lightweight mitigation is a per-IP cap as a first gate in
RequireAPIKey, before any key parsing or bucket allocation:This would require passing a second
RateLimiter(IP-based) intoRequireAPIKeyalongside the existing per-key one.