How a Tiny URL Parameter Let Me Hijack a GitHub Gist Account and Earn $10k
Security researcher William Bowling discovered that Rails' url_for helper can be abused via controllable parameters to create open redirects and account takeover on GitHub Gist, allowing theft of OAuth tokens and earning a $10,000 bounty.
0x01 Introduction
Security researcher William Bowling discovered that the Rails url_for helper can be manipulated to generate arbitrary URLs, which he used to take over a GitHub Gist account and earn a $10,000 bounty.
0x02 Vulnerability Discovery
The url_for method accepts many options that can be controlled via a hash. By supplying a crafted hash, parameters such as :script_name can be injected into the generated URL, leading to a reflected XSS and, more importantly, an open redirect. :only_path – if true, returns a relative URL (default false). :protocol – protocol to use, default http. :host – target host; required when :only_path is false. :subdomain – subdomain part, removed if false. :domain – domain part. :tld_length – number of TLD labels, used with subdomain or domain. :port – optional port. :anchor – anchor name appended to path. :params – query parameters to append. :trailing_slash – adds a trailing slash when true. :script_name – application path relative to domain root.
In GitHub code, links are built with
<%= url_for(request.query_parameters.merge(only_path: true)) %>. Supplying ?script_name=javascript:alert(1)// produces a link with a javascript: scheme:
<a class="link" href="<%= url_for(request.query_parameters.merge(only_path: true)) %>">
Click me
</a>Although the XSS is low‑severity and blocked by CSP, the open redirect can be abused.
0x03 Exploitation
By adding a script_name parameter to the redirect URL, the attacker can control the host part of the final location. Using script_name=.attacker.domain redirects the victim to the attacker’s domain.
The same technique works in an application controller that builds a redirect URL with only_path: true. A crafted request such as:
curl -i 'http://local.dev?source=message&script_name=ggg'results in a 302 response pointing to http://local.devggg/welcome/index:
HTTP/1.1 302 Found
Location: http://local.devggg/welcome/index
...Applying this to GitHub’s Gist OAuth flow, the attacker can capture browser_session_id and code parameters, then reuse them with a malicious script_name to obtain a valid OAuth token for the Gist account, effectively taking over the account.
William Bowling demonstrated the attack, logged into a Gist account, and received a $10,000 bounty for the vulnerability.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
