No rate limiting on the Basic-Auth-protected /metrics endpoint #101
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
REPO_POLICIES.mdrequires "rate limiting on password-based authentication endpoints" before 1.0, and explicitly carves out only high-entropy API keys: "API keys are high-entropy and not susceptible to brute force, so they are exempt."/metricsis protected by HTTP Basic Auth with an operator-chosen username and password (internal/server/routes.go:54-63;MetricsAuth()atinternal/middleware/middleware.go:189-205; credentials fromMETRICS_USERNAME/METRICS_PASSWORDatinternal/config/config.go:161-162). That is password-based auth, not an API key, so the exemption does not apply.There is no rate limiting anywhere in the repository. A grep for
throttle|limiter|x/time/rate|httprate|ratelimitacross all*.goreturns nothing, andgo.modcarries no rate-limiting dependency. Credentials can be brute-forced at whatever rate the network allows.The underlying
github.com/99designs/basicauth-godoes usecrypto/subtle.ConstantTimeCompare, so timing attacks are already handled — this issue is specifically about attempt-rate, which constant-time comparison does nothing for.Definition of done
/metricsroute group usinggithub.com/go-chi/httprate— this is the decided default for HTTP rate limiting in Go repos; do not hand-roll a limiter and do not substitute a different library.go getandgo mod tidyis run, sogo.modandgo.sumare both updated and the module hash is recorded ingo.sum(this satisfies the hash-pinning rule for Go modules).internal/middleware/middleware.go:110-170already implements correct trusted-proxy-gated client IP extraction (realIP(), honouringX-Real-IP/X-Forwarded-Foronly whenRemoteAddris inside RFC1918 / loopback / ULA). Reuse that logic — do not usehttprate.KeyByIPdirectly if it would trust forwarded headers unconditionally, and do not duplicate the trusted-proxy list.429 Too Many Requests. The response body must not leak whether the username or the password was wrong, or whether/metricsis even configured.429; a request from a different IP is unaffected by another IP's exhausted budget; and a normal scrape cadence is not throttled. Tests must not sleep for the full window — make the window injectable or keep it short enough that the suite stays well inside the repo's 20-secondmake testceiling.METRICS_USERNAME/METRICS_PASSWORDdocumentation.make checkis green, andTODO.mdis updated in the same commit as the work.The finishing commit's title must end with
(closes #N)referencing this issue.Notes
/metricsis not mounted at all whenMETRICS_USERNAMEis empty (internal/server/routes.go:54), so there is no unauthenticated-by-default exposure to fix — this issue is only about throttling attempts when the endpoint is enabled.Out of scope
Security response headers (#98),
http.Servertimeouts (#99), and CORS scoping (#100) are tracked separately. Rate limiting the public read-only routes is not required by policy and is not in scope here.