Skip to content

Fix unbounded server-controlled retry sleep on HTTP 429 (OKTA-1235975) - #1707

Open
prachi-okta wants to merge 2 commits into
masterfrom
OKTA-1235975-unbounded-429-retry-sleep
Open

prachi-okta wants to merge 2 commits into
masterfrom
OKTA-1235975-unbounded-429-retry-sleep

Conversation

@prachi-okta

@prachi-okta prachi-okta commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary

OKTA-1235975: the SDK's 429 retry delay was computed entirely from the server-supplied x-rate-limit-reset header with no upper bound, so a malicious or MitM server could force the client thread to sleep indefinitely. Since this sleep can happen inside OAuth2ClientCredentials.applyToParams (synchronized), one blocked call could stall every other caller waiting on token refresh — a client-side DoS triggerable by untrusted response data.

  • RetryUtil.get429DelayMillis now clamps the computed delay to a maxDelayMillis ceiling.
  • OktaHttpRequestRetryStrategy derives that ceiling from retryMaxElapsed if explicitly configured, otherwise falls back to the same 20s cap already used for 503/504/IOException retries — so 429 is no longer the exception.
  • DefaultClientBuilder now actually wires clientConfig.getRetryMaxElapsed() into the strategy (previously set on ClientConfiguration but never read anywhere — dead config).
  • README updated to document the new default cap and the existing requestTimeout/setRetryMaxElapsed escape hatch for anyone who needs a longer wait.

Separately (own commit, unrelated root cause): bumps httpclient5 5.6.2 → 5.6.4 to resolve CVE-2026-64607 (connection-leak DoS in the classic I/O model on malformed Content-Encoding headers), found while chasing an unrelated stalled release:prepare run. This supersedes the existing dependabot/maven/.../httpclient5-5.6.3 branch.


Have added more details of the fix in the comments: https://oktainc.atlassian.net/browse/OKTA-1235975

The 429 retry delay was computed entirely from the server-supplied
x-rate-limit-reset header with no upper bound, so a malicious or MitM
server could force the client thread to sleep indefinitely. Since this
can happen inside OAuth2ClientCredentials.applyToParams (synchronized),
one blocked thread could stall every other caller waiting on token
refresh.

RetryUtil.get429DelayMillis now clamps the computed delay to a
maxDelayMillis ceiling. OktaHttpRequestRetryStrategy derives that
ceiling from retryMaxElapsed if explicitly configured, otherwise falls
back to the same 20s cap already used for 503/504/IOException retries.
DefaultClientBuilder now actually wires clientConfig.getRetryMaxElapsed()
into the strategy, which was previously set on ClientConfiguration but
never read anywhere.

Co-Authored-By: Claude Code
httpclient5 5.6.2 fails to release the underlying connection back to
the connection manager on an invalid/unsupported Content-Encoding
header value in the classic I/O model, allowing connection pool
exhaustion (DoS). Fixed upstream in 5.6.3+; bumping to the latest
5.6.x patch release.

Co-Authored-By: Claude Code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant