Deleting branch and merge request from a repository does not hide or delete the changes made in the merge request

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 #2795371 by f3rn0s on 2024-10-21, assigned to @ottilia_westerlund:

Report | Attachments | How To Reproduce

Report

Summary

GitLab provides mechanisms for users to delete merge requests and associated branches, but currently the functionality will leave behind orphaned commits that are never automatically cleaned. An attacker can enumerate through the merge requests visible from the web UI or API, and spot missing incremental IDs. With these IDs, the attacker can then check to see if there exists a git remote that matches the deleted merge request, and then recover the changes.

Steps to reproduce
  1. Create a repository on GitLab
  2. Create a branch and push sensitive information
  3. Create a merge request for the branch
  4. Delete the branch, then delete the merge request
  5. Clone a fresh copy of the repository and use git ls-remote to find the still persisting git remote for the merge request.
  6. Use git fetch origin sha_hash_of_commit to pull the commit of the merge request down into the local repo.
  7. Use git checkout sha_hash_of_commit to checkout the commit.
  8. Use git log -p -v to observe the changes made in the commit, and observe any sensitive information remaining.

I have created a test repository here:

https://gitlab.com/f3rn0s/theres-no-such-thing-as-flags/

From the web UI you can observe there is an open merge request (identified as 2) that implies that there is some missing merge request. Using a tool I developed, I can quickly identify that there is a hidden remote that points at this now deleted merge request:

image.png

To manually re-create these steps you would use git directly:

image.png

image.png

We can observe from these screenshots that an anonymous user can retrieve the flag from the repository, even though from the maintainers perspective they have deleted both the branch the flag existed on, as well as the merge request originally created.

Impact

Users who are not aware of this functionality may erroneously believe that after deleting the merge request, and the branch the changes existing on, they have purged the repository of sensitive information. The sensitive information will then persist inside the repository and can potentially be gathered by an attacker.

What is the expected correct behavior?

Gitlab provides two modals that pop up during this process. Once when deleting the branch:

image.png

And once when deleting the merge request:

image.png

Both of these modals state that 'data loss could occur' which implies to the user that they are deleting data from the repository.

GitLab should seek to better clarify that deleting a merge request does not delete the underlying remote, or to change the functionality to remove the merge request remote when deleting the merge request.

Impact

Security impact depends on the repository affected. I first observed this behaviour on my own companys repositories, and the impact if discovered by an attacker would have been:

  • (For my company) Access to a red teaming report that contained redaction fails (hence why the MR and branch were deleted to remove the report from GitLab).
  • (For my company) Access to internal pricing information

An exploration of public facing repositories to expose similar issues may find similar levels of risk.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section: