CVE-2026-54603 Overview
CVE-2026-54603 affects the oauth2 Ruby gem, a wrapper for the OAuth 2.0 and 2.1 authorization frameworks including OpenID Connect (OIDC). Versions from 0.4.0 through 2.0.21 mishandle protocol-relative redirect locations returned to OAuth2::Client#request. A Location header value such as //attacker.example overrides the original request authority. The client then follows the redirect and forwards the bearer Authorization header to an attacker-controlled host, leaking the credential. The issue is classified under [CWE-200] (Exposure of Sensitive Information) and is resolved in version 2.0.22.
Critical Impact
A malicious or compromised OAuth endpoint can steal bearer tokens by returning a protocol-relative redirect, exposing accounts and downstream APIs the token grants access to.
Affected Products
- oauth2 Ruby gem versions 0.4.0 through 2.0.21
- Ruby applications and services depending on the oauth2 gem for OAuth 2.0 / 2.1 flows
- Applications using OpenID Connect (OIDC) client functionality provided by the gem
Discovery Timeline
- 2026-07-28 - CVE-2026-54603 published to NVD
- 2026-07-29 - Last updated in NVD database
Technical Details for CVE-2026-54603
Vulnerability Analysis
The oauth2 gem follows HTTP redirects returned by servers during OAuth request flows. When the response contains a Location header, the client merges the redirect URL with the original request URL and reissues the request, preserving request options including the Authorization header carrying the bearer token.
A protocol-relative URL of the form //host/path omits the scheme. Ruby's URI#merge interprets such a value by replacing the authority component of the base URL while retaining the scheme. An attacker who controls or compromises an OAuth response can return Location: //attacker.tld/path to redirect the client to an arbitrary host. Because the request options are not sanitized before the follow-up call, the bearer token is transmitted to the attacker.
Root Cause
The root cause is missing validation on redirect authority combined with unconditional propagation of request options. The pre-patch code in lib/oauth2/client.rb used response.response.env.url.merge(location) and forwarded the original req_opts on the redirected request, without verifying that the destination host matches the origin or stripping sensitive headers on cross-origin redirects.
Attack Vector
Exploitation requires an attacker to control an HTTP response processed by OAuth2::Client#request. This can occur through a compromised OAuth provider, a man-in-the-middle position on unencrypted transports, an open-redirect on the target's authorization server, or a malicious resource endpoint the client contacts. No user interaction or authentication is required by the attacker; the victim application executes the redirect automatically.
end
location = response.headers["location"]
if location
- full_location = response.response.env.url.merge(location)
- request(verb, full_location, req_opts)
+ current_location = response.response.env.url
+ full_location = resolve_redirect_location(current_location, location)
+ request(verb, full_location, sanitize_redirect_options(req_opts, current_location, full_location))
else
error = Error.new(response)
raise(error, "Got #{status} status code, but no Location header was present")
Source: GitHub commit 0f0a474. The patch introduces resolve_redirect_location to correctly interpret the redirect target and sanitize_redirect_options to strip credentials on cross-origin redirects.
Detection Methods for CVE-2026-54603
Indicators of Compromise
- Outbound HTTPS or HTTP requests from Ruby application hosts to unexpected external domains carrying Authorization: Bearer headers.
- HTTP responses received by application services containing Location headers beginning with // (protocol-relative) during OAuth token exchange or resource fetches.
- Repeated 3xx redirect chains originating from OAuth provider endpoints followed by requests to previously unseen hosts.
Detection Strategies
- Inventory Ruby application dependencies and flag any Gemfile.lock entry for oauth2 with a version between 0.4.0 and 2.0.21 inclusive.
- Inspect egress proxy logs for OAuth client traffic where the destination host of a redirected request differs from the original OAuth provider host.
- Add web application firewall or reverse proxy rules on trusted OAuth endpoints to alert on Location header values that start with //.
Monitoring Recommendations
- Enable structured logging in the oauth2 gem or wrapping HTTP client (e.g., Faraday) to record every redirect target and correlate with the initial request host.
- Monitor secret-scanning and token-revocation telemetry from identity providers for anomalous token replays from unknown IP addresses following a redirect event.
- Alert on Ruby process outbound connections to newly observed domains during the OAuth token lifecycle window.
How to Mitigate CVE-2026-54603
Immediate Actions Required
- Upgrade the oauth2 gem to version 2.0.22 in all Ruby applications and rebuild dependent services.
- Rotate any bearer tokens, refresh tokens, and client secrets that may have transited a vulnerable client since deployment of affected versions.
- Audit OAuth provider configurations to confirm no open-redirect conditions exist that could be chained with this flaw.
Patch Information
The fix is available in oauth2 version 2.0.22, released on the project's GitHub. See the GitHub Release v2.0.22 and the GitHub Security Advisory GHSA-pp92-crg2-gfv9 for full details. The patch resolves redirect locations through resolve_redirect_location and sanitizes request options on cross-origin redirects via sanitize_redirect_options.
Workarounds
- Pin OAuth endpoints to fully qualified HTTPS URLs and restrict outbound network egress from Ruby workloads to an allowlist of known identity provider hosts.
- Wrap OAuth2::Client#request in a custom subclass that validates each redirect target's host against the original request authority and strips the Authorization header on any cross-origin follow-up.
- Disable automatic redirect following in the underlying HTTP adapter if the application does not require it, forcing explicit handling of 3xx responses.
# Update the oauth2 gem to the patched release
bundle update oauth2 --conservative
# Verify the installed version is 2.0.22 or later
bundle exec gem list oauth2
# Alternatively, pin in Gemfile
# gem "oauth2", ">= 2.0.22"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

