fix(security): close confirmed findings from the 2026-10-15 hunt (#166)

Seven findings are fixed. Each fix has a regression test.

- Compare X-Forwarded-Host and the serving host case-insensitively, so a
  case variant cannot widen the session cookie Domain.
- Reject a future iat on the opaque introspection path.
- Serve the cached parsed JWKS inside the signature-refresh cooldown.
- Release the half-open circuit slot when a probe panics.
- Cap requests that wait for provider initialisation at 512. Extra
  requests receive 503 with Retry-After.
- Cap cookie deletion headers at 32 cookie names per response.
- Cap front-channel sid markers at 1000, so unauthenticated requests
  cannot evict backchannel or jti replay markers.
This commit is contained in:
2026-10-16 00:47:35 +01:00
committed by GitHub
parent f0af6282dc
commit 9ab7220828
9 changed files with 371 additions and 2 deletions
+5
View File
@@ -371,6 +371,11 @@ func enforceIatAge(claims map[string]interface{}, maxAge time.Duration) *bearerE
if time.Since(iat) > maxAge {
return newBearerError(bearerErrInvalidToken, "token iat outside age bound")
}
// The opaque introspection path never runs jwt.Verify, so a future iat
// would otherwise defeat the age bound for the token's whole lifetime.
if time.Until(iat) > ClockSkewToleranceFuture {
return newBearerError(bearerErrInvalidToken, "token iat in the future")
}
return nil
}