OSV 1.4.0 · github-reviewed · 修改于 2026-07-29 00:27
发布时间
2026-07-29 00:27
GitHub 审查时间
2026-07-29 00:27
NVD 发布时间
—
源文件
advisories/github-reviewed/2026/07/GHSA-prq8-7wvh-44qh/GHSA-prq8-7wvh-44qh.json
When an application uses OAuth::Consumer to request OAuth 1.0 request tokens or
access tokens, the token request helper follows 300..399 redirects returned by
the OAuth server. In affected versions, OAuth::Consumer#token_request parses the
raw Location header, follows the redirect recursively, and can mutate the
consumer's configured site when the redirect points to a different host with
the same path.
The result is a cross-origin signed-request disclosure primitive: if an OAuth server token endpoint returns a redirect whose target an attacker controls, the client can re-sign the token request and send OAuth 1.0 request metadata, including the OAuth signature, nonce, timestamp, consumer key, and any request parameters included in the signature base string, to the attacker-controlled host. The same behavior can also be used as an SSRF or confused-deputy primitive because the application server follows the redirect and sends the next request from its own network position.
oauth v1.1.5 and prior versions back to and including v0.5.5.
OAuth::Consumer#token_request, which is used by
the documented request-token and access-token flows.Patched version: oauth v1.1.6.
A consumer that calls OAuth::Consumer#get_request_token,
OAuth::Consumer#get_access_token, or lower-level token request helpers against
an OAuth server whose token endpoint redirect target can be influenced may lose
three security properties:
oauth_consumer_keyoauth_signature_methodoauth_timestampoauth_nonceoauth_versionoauth_signatureThe disclosed OAuth 1 signature is not equivalent to an OAuth 2 bearer token: it is bound to the signed request, timestamp, nonce, HTTP method, and request URL. However, it can still disclose sensitive integration metadata, may be replayable within the receiver's accepted nonce/timestamp window in some deployments, and can expose application-server reachability to attacker-selected hosts.
lib/oauth/consumer.rb
at tag v1.1.5:
def token_request(http_method, path, token = nil, request_options = {}, *arguments)
request_options[:token_request] ||= true
response = request(http_method, path, token, request_options, *arguments)
case response.code.to_i
when (200..299)
# parse token response
when (300..399)
# Parse redirect to follow
uri = URI.parse(response["location"])
our_uri = URI.parse(site)
# Guard against infinite redirects
response.error! if uri.path == path && our_uri.host == uri.host
if uri.path == path && our_uri.host != uri.host
options[:site] = "#{uri.scheme}://#{uri.host}"
@http = create_http
end
token_request(http_method, uri.path, token, request_options, arguments)
when (400..499)
raise OAuth::Unauthorized, response
else
response.error!
end
end
The vulnerable behavior has several parts:
response["location"] is trusted as the next token request target.300..399 response.options[:site] and rebuild
the underlying HTTP client.The vulnerable path is reachable through the normal OAuth 1 token exchange:
consumer = OAuth::Consumer.new(
consumer_key,
consumer_secret,
site: "https://provider.example"
)
request_token = consumer.get_request_token
If https://provider.example/oauth/request_token returns a redirect to an
attacker-controlled host, the library follows that redirect as part of the token
request flow. A realistic trigger is an OAuth provider, gateway, or reverse proxy
that emits Location based on user-controlled or tenant-controlled input, or a
malicious tenant-controlled OAuth endpoint in a multi-tenant integration.
No application-level redirect handling is required. The redirect is followed inside the gem before the application receives the token response.
A vulnerable application is one that uses OAuth::Consumer to perform an OAuth
1 token exchange against a token endpoint that can be made to return a redirect
to another origin.
Example shape:
consumer = OAuth::Consumer.new(
consumer_key,
consumer_secret,
site: "https://provider.example"
)
consumer.get_request_token
If https://provider.example/oauth/request_token responds with a 30x redirect
whose Location points to https://attacker.example/..., affected versions may
follow that redirect as part of the token request flow. The redirected request is
then generated and signed by the application server for the new destination.
Depending on the configured OAuth request scheme, OAuth 1 parameters may be sent
in the Authorization header, request body, or query string.
Expected vulnerable behavior:
Expected patched behavior:
token_request_cross_origin_redirects.Reject cross-origin token endpoint redirects by default and require explicit opt-in for integrations that intentionally depend on that behavior.
The fix released in v1.1.6 does the following:
current_uri = token_request_uri(path)
redirected_uri = token_request_redirect_uri(current_uri, response)
response.error! unless redirected_uri
redirect_count = request_options[:token_request_redirect_count].to_i + 1
response.error! if redirect_count > token_request_max_redirects(request_options)
response.error! if token_request_cross_origin?(current_uri, redirected_uri) &&
!token_request_cross_origin_redirects?(request_options)
redirect_options = request_options.merge(token_request_redirect_count: redirect_count)
token_request(http_method, token_request_redirect_path(current_uri, redirected_uri), token, redirect_options, *arguments, &block)
The fix intentionally preserves same-origin redirect compatibility while making
cross-origin token endpoint redirects an explicit choice. It also avoids placing
internal redirect state in request_options passed to OAuth signing.
Until a patched release is available, applications can reduce exposure by doing one or more of the following:
These mitigations reduce exploitability but do not remove the vulnerable redirect logic from the gem.
Found during the follow-up audit for GHSA-pp92-crg2-gfv9.
Reporter/coordinator: Peter H. Boling (pboling).
oauth v1.1.6