A bypass on GitLab’s Login Email Verification via OAuth ROPC flow.
This writeup is to raise awareness for users and developers implementing OAuth ROPC flow.
The Resource Owner Password Credentials(ROPC) is one of the Open Authorization(OAuth) flow with a “password” grant type. This grant type requires the username and password of the resource owner in order to acquire an access token from the authorizing server.
How it works?
Some organizations decide not to implement this grant type on their applications for some reason. As a bug bounty hunter, this type of authorization/authentication flow raises some questions like, “What if there is an additional layer of security on the account such as MFA / email verification?” . I think only testing can answer it.
On Hackerone, there are quite a lot of programs that have OAuth implemented but few are implementing the ROPC flow. I found some programs that have this flow/grant type supported by their OAuth implementation. Most of these programs implemented the flow correctly. But on some programs(private and undisclosed reports) I manage to use this flow to bypass their 2FA. The reports were properly validated, triaged and resolved eventually.
So, I tried to look for more programs that support this flow and one of them is Gitlab. In their OAuth documentation about ROPC flow, there are 2 types of request. One is with an OAuth app client credentials and second is without it.
Upon testing, this flow was not able to bypass MFA/2FA. At that moment, I immediately thought of not conducting further tests. However, I remembered that GitLab enforced an additional layer of security on gitlab.com despite 2FA is disabled and that is the Login Email Verification. This feature provides an additional layer of GitLab account security. This feature instantly locks the account when one of the following conditions is met:
- There are three or more failed sign-in attempts in 24 hours.
- A user attempts to sign in from a new IP address and the check_ip_address_for_email_verification feature flag(on self hosted instance) is enabled.
Realistically, some if not most users prefer not to implement 2FA on their account especially if there is already an implemented security feature such as the email verification on login.
I was able to confirm that logging in an account from a new IP/device via web login will trigger the email verification which instantly revokes all current sessions and locks the account. The account will be unlocked if the 6 digit code sent to the target user’s email is provided correctly.
Upon further testing, the ROPC flow does not implement any form of additional security if the 2FA is disabled. Unlike in web login, there is an email verification.
From an attacker’s point of view, it is impossible to take over or even access a compromised account via web login. But it is indeed possible using the ROPC flow by sending the curl request below which the authorizing server issues an access token with “api” scope. A scope with complete read/write access to the API, including all groups and projects, the container registry, the dependency proxy, and the package registry
curl — data “grant_type=password&username=<your_username>&password=<your_password>” — request POST “https://gitlab.com/oauth/token"
Upon confirming this, I quickly filed a Hackerone Report[#2676025] . After a week, GitLab responded with:
And I responded:
It is clear on my report that I was pertaining about “compromised” accounts to takeover. The email verification should be a mitigation for this possibility. However it failed to do so.
After my disclosure request was approved, they responded with:
But the real question is: What if the instance owner turned on the said feature in assurance that it is an “Additional Layer of Security”?. However, due to the ROPC flow, it is ineffective.
In my own opinion, its just pointless to implement an “additional layer of security” if it can be bypassed with another feature.
I accepted the closure of the report as Informative. They accepted it as a “bug” but not a vulnerability :)
The bug still EXISTS and GitLab refused to put a fix on the bug which leaves the said “security feature” vulnerable.