Security finding
An unauthenticated JWT bearing an unknown kid invalidates the shared JWKS cache and forces a new JWKS fetch on every retry.
Evidence
The pinned go-mcp-oauth-sdk refreshes JWKS immediately after an unknown unverified kid. A still-missing key is classified as transient, and internal/verification correctly avoids negative-caching transient errors. There is no shared refresh cooldown or request coalescing.
Reproduction
After warming the JWKS cache, changing only a compact JWT's unsigned header to an absent kid caused 12 identical retries to make 12 additional JWKS HTTP requests. A valid signature was unnecessary because key resolution occurs before signature verification.
Impact
A network-reachable unauthenticated client can bypass the configured JWKS cache TTL, amplify traffic to the IdP, and occupy LDAP slots while outbound HTTP is in flight. The per-request HTTP timeout and response-size bound limit individual calls, but not retry rate or concurrent refreshes.
Proposed direction
Implement upstream refresh coalescing and a bounded global refresh cooldown/rate limit while retaining safe key-rotation recovery. Do not turn all missing-key failures into permanently negative-cached results. Consider caller admission/rate controls in this helper as defense in depth.
Validation
Add concurrent and repeated unknown-kid tests proving one refresh per configured cooldown/coalescing window, plus a genuine key-rotation success case.
Security finding
An unauthenticated JWT bearing an unknown
kidinvalidates the shared JWKS cache and forces a new JWKS fetch on every retry.Evidence
The pinned
go-mcp-oauth-sdkrefreshes JWKS immediately after an unknown unverifiedkid. A still-missing key is classified as transient, andinternal/verificationcorrectly avoids negative-caching transient errors. There is no shared refresh cooldown or request coalescing.Reproduction
After warming the JWKS cache, changing only a compact JWT's unsigned header to an absent
kidcaused 12 identical retries to make 12 additional JWKS HTTP requests. A valid signature was unnecessary because key resolution occurs before signature verification.Impact
A network-reachable unauthenticated client can bypass the configured JWKS cache TTL, amplify traffic to the IdP, and occupy LDAP slots while outbound HTTP is in flight. The per-request HTTP timeout and response-size bound limit individual calls, but not retry rate or concurrent refreshes.
Proposed direction
Implement upstream refresh coalescing and a bounded global refresh cooldown/rate limit while retaining safe key-rotation recovery. Do not turn all missing-key failures into permanently negative-cached results. Consider caller admission/rate controls in this helper as defense in depth.
Validation
Add concurrent and repeated unknown-
kidtests proving one refresh per configured cooldown/coalescing window, plus a genuine key-rotation success case.