From 225b53bfa7f7a8aa565d47164a66301b756c8d13 Mon Sep 17 00:00:00 2001 From: mrhid6 Date: Thu, 13 Aug 2026 08:31:12 +0000 Subject: [PATCH] fix: Throttle audit logging for expired API token use Every request presenting an expired token wrote a token.expired_use audit row, and RateLimitTokens only applies once a session exists, so a rejected token was never rate-limited. A looping job with one expired token could write an unbounded number of audit rows, drowning the real audit trail. services.ShouldLogExpiredTokenUse now dedupes to at most one token.expired_use record per token per minute, mirroring the throttle TouchAPIToken already uses for last-used. It lives in services rather than auth because the storage concern belongs beside the token's other storage-backed state. The first use per window is still recorded, which is what makes a forgotten job visible. --- server/internal/auth/middleware.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/server/internal/auth/middleware.go b/server/internal/auth/middleware.go index e17acc3..151e602 100644 --- a/server/internal/auth/middleware.go +++ b/server/internal/auth/middleware.go @@ -135,9 +135,13 @@ func sessionFromToken(c *gin.Context) (*Session, bool) { tok, err := services.ResolveAPIToken(raw) if errors.Is(err, services.ErrTokenExpired) { // Recorded rather than only refused: an expired token still being - // presented is how a forgotten CI job becomes visible. - services.LogEvent(tok.InstanceID, "token.expired_use", tok.Name, "", "", - fmt.Sprintf("expired token '%s' was used", tok.Name)) + // presented is how a forgotten CI job becomes visible. Throttled to + // once per token per minute, or a looping job writes an unbounded + // stream of audit rows instead of one. + if services.ShouldLogExpiredTokenUse(tok.TokenID) { + services.LogEvent(tok.InstanceID, "token.expired_use", tok.Name, "", "", + fmt.Sprintf("expired token '%s' was used", tok.Name)) + } c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "token expired", "code": "token_expired"}) return nil, false }