Audit review (rounds 1-31): fix confirmed issues, remove dead code, harden tests

Security/correctness fixes:
- fail-open token validation preserved with lenient-audience; access token that
  fails verification and has no ID token to corroborate now fails closed
- token_manager blacklist-expiry: fix impossible tautology (x>24h && x<24h)
- constant-time OAuth state compare; clear state/nonce/code_verifier on
  callback token-exchange failure to prevent replay of half-failed flows
- StopAllTasks gated on last-instance close
- background-task panic recovery; remove task-registry counter leak
- circuit breaker half-open: release probe slot; CB + per-session outcome
  recorded once per refresh operation, not once per waiter
- Redis connection pool: handle nil receive when pool closed concurrently
- FileStore: atomic temp-write + rename
- errors_recovery health-check data race -> atomic

Test-isolation / hardening:
- reset helpers for Once-pinned global cache manager and transport pool
- coverage: utils 70->93% (redirect URL security contract); fuzz targets for
  bearer parsers; concurrent ServeHTTP race tests for the shared request path

Dead-code removal (verified orphaned, build+suite green): internal/providers
(30 files, 0 importers), internal/compat, internal/features, input_validation.

Verified: govulncheck, go mod tidy, yaegi-validate, cross-compile (darwin+
linux), golangci-lint (new-from-rev clean), 3x full race+shuffle green.
This commit is contained in:
2026-08-12 23:08:03 +01:00
parent f728f61777
commit 2ff14556d0
66 changed files with 1064 additions and 10046 deletions
+20 -4
View File
@@ -190,6 +190,7 @@ func (t *TraefikOidc) validateStandardTokensRS(rs *requestState) (bool, bool, bo
// JWT access token present.
accessTokenValid := false
lenientAudienceOnly := false
if err := t.verifyToken(rs.accessToken); err != nil {
errMsg := err.Error()
if strings.Contains(errMsg, "invalid audience") || strings.Contains(errMsg, "audience") {
@@ -199,7 +200,10 @@ func (t *TraefikOidc) validateStandardTokensRS(rs *requestState) (bool, bool, bo
}
return false, false, true
}
// Fall through to ID-token validation.
// Lenient audience validation: the token's signature verified; only
// the audience was left unchecked. Fall through to ID-token
// validation, remembering the access token was structurally valid.
lenientAudienceOnly = true
}
} else {
accessTokenValid = true
@@ -209,10 +213,22 @@ func (t *TraefikOidc) validateStandardTokensRS(rs *requestState) (bool, bool, bo
if accessTokenValid {
return t.validateTokenExpiryRS(rs, rs.accessToken)
}
if rs.refreshToken != "" {
return true, true, false
if lenientAudienceOnly {
// Access token signature verified; audience check was lenient and
// there is no ID token to compare against. Treat as authenticated.
if rs.refreshToken != "" {
return true, true, false
}
return true, false, false
}
return true, false, false
// Access token failed verification (expired, bad signature, issuer, ...)
// and there is no ID token to corroborate it. Fail closed rather than
// trusting an unverified token: refresh if possible, otherwise force
// re-authentication.
if rs.refreshToken != "" {
return false, true, false
}
return false, false, true
}
if err := t.verifyToken(rs.idToken); err != nil {