Follow-up from #1386 (LOW, non-blocking). #1386 fixed the amplification-DoS (bad tokens no longer trigger a cache-destroying rebuild each; rebuilds bounded to ~1/10s). A residual remains: go-oidc v3.18.0's RemoteKeySet.verify has no internal cooldown, so each bad-signature token with an unknown kid still costs ONE JWKS fetch (1:1 proportional proxying to the provider's CDN-backed endpoint), unavoidable at our layer without wrapping oidc.KeySet. This is go-oidc's spec-mandated design and non-amplifying, but under sustained spam it still forwards load to the IdP.
Optional hardening: wrap oidc.KeySet with a short-lived negative cache of recently-seen-unknown kids (or a per-source token-bucket) so repeated unknown-kid tokens short-circuit to 401 without a fetch, while a genuinely new rotation kid still refreshes once. Keep fail-closed. Also revisit if go-oidc adds an internal refresh cooldown in a later version (bump + drop the wrapper).
Ref: Fable security review of #1386.
Follow-up from #1386 (LOW, non-blocking). #1386 fixed the amplification-DoS (bad tokens no longer trigger a cache-destroying rebuild each; rebuilds bounded to ~1/10s). A residual remains: go-oidc v3.18.0's RemoteKeySet.verify has no internal cooldown, so each bad-signature token with an unknown kid still costs ONE JWKS fetch (1:1 proportional proxying to the provider's CDN-backed endpoint), unavoidable at our layer without wrapping oidc.KeySet. This is go-oidc's spec-mandated design and non-amplifying, but under sustained spam it still forwards load to the IdP.
Optional hardening: wrap oidc.KeySet with a short-lived negative cache of recently-seen-unknown kids (or a per-source token-bucket) so repeated unknown-kid tokens short-circuit to 401 without a fetch, while a genuinely new rotation kid still refreshes once. Keep fail-closed. Also revisit if go-oidc adds an internal refresh cooldown in a later version (bump + drop the wrapper).
Ref: Fable security review of #1386.